You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

tool.go 12 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package base
  5. import (
  6. "crypto/hmac"
  7. "crypto/md5"
  8. "crypto/rand"
  9. "crypto/sha1"
  10. "encoding/hex"
  11. "fmt"
  12. "hash"
  13. "math"
  14. "strconv"
  15. "strings"
  16. "time"
  17. )
  18. // Encode string to md5 hex value
  19. func EncodeMd5(str string) string {
  20. m := md5.New()
  21. m.Write([]byte(str))
  22. return hex.EncodeToString(m.Sum(nil))
  23. }
  24. // GetRandomString generate random string by specify chars.
  25. func GetRandomString(n int, alphabets ...byte) string {
  26. const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  27. var bytes = make([]byte, n)
  28. rand.Read(bytes)
  29. for i, b := range bytes {
  30. if len(alphabets) == 0 {
  31. bytes[i] = alphanum[b%byte(len(alphanum))]
  32. } else {
  33. bytes[i] = alphabets[b%byte(len(alphabets))]
  34. }
  35. }
  36. return string(bytes)
  37. }
  38. // http://code.google.com/p/go/source/browse/pbkdf2/pbkdf2.go?repo=crypto
  39. func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
  40. prf := hmac.New(h, password)
  41. hashLen := prf.Size()
  42. numBlocks := (keyLen + hashLen - 1) / hashLen
  43. var buf [4]byte
  44. dk := make([]byte, 0, numBlocks*hashLen)
  45. U := make([]byte, hashLen)
  46. for block := 1; block <= numBlocks; block++ {
  47. // N.B.: || means concatenation, ^ means XOR
  48. // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
  49. // U_1 = PRF(password, salt || uint(i))
  50. prf.Reset()
  51. prf.Write(salt)
  52. buf[0] = byte(block >> 24)
  53. buf[1] = byte(block >> 16)
  54. buf[2] = byte(block >> 8)
  55. buf[3] = byte(block)
  56. prf.Write(buf[:4])
  57. dk = prf.Sum(dk)
  58. T := dk[len(dk)-hashLen:]
  59. copy(U, T)
  60. // U_n = PRF(password, U_(n-1))
  61. for n := 2; n <= iter; n++ {
  62. prf.Reset()
  63. prf.Write(U)
  64. U = U[:0]
  65. U = prf.Sum(U)
  66. for x := range U {
  67. T[x] ^= U[x]
  68. }
  69. }
  70. }
  71. return dk[:keyLen]
  72. }
  73. // verify time limit code
  74. func VerifyTimeLimitCode(data string, minutes int, code string) bool {
  75. if len(code) <= 18 {
  76. return false
  77. }
  78. // split code
  79. start := code[:12]
  80. lives := code[12:18]
  81. if d, err := StrTo(lives).Int(); err == nil {
  82. minutes = d
  83. }
  84. // right active code
  85. retCode := CreateTimeLimitCode(data, minutes, start)
  86. if retCode == code && minutes > 0 {
  87. // check time is expired or not
  88. before, _ := DateParse(start, "YmdHi")
  89. now := time.Now()
  90. if before.Add(time.Minute*time.Duration(minutes)).Unix() > now.Unix() {
  91. return true
  92. }
  93. }
  94. return false
  95. }
  96. const TimeLimitCodeLength = 12 + 6 + 40
  97. // create a time limit code
  98. // code format: 12 length date time string + 6 minutes string + 40 sha1 encoded string
  99. func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string {
  100. format := "YmdHi"
  101. var start, end time.Time
  102. var startStr, endStr string
  103. if startInf == nil {
  104. // Use now time create code
  105. start = time.Now()
  106. startStr = DateFormat(start, format)
  107. } else {
  108. // use start string create code
  109. startStr = startInf.(string)
  110. start, _ = DateParse(startStr, format)
  111. startStr = DateFormat(start, format)
  112. }
  113. end = start.Add(time.Minute * time.Duration(minutes))
  114. endStr = DateFormat(end, format)
  115. // create sha1 encode string
  116. sh := sha1.New()
  117. sh.Write([]byte(data + SecretKey + startStr + endStr + ToStr(minutes)))
  118. encoded := hex.EncodeToString(sh.Sum(nil))
  119. code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded)
  120. return code
  121. }
  122. // AvatarLink returns avatar link by given e-mail.
  123. func AvatarLink(email string) string {
  124. if Service.EnableCacheAvatar {
  125. return "/avatar/" + EncodeMd5(email)
  126. }
  127. return "//1.gravatar.com/avatar/" + EncodeMd5(email)
  128. }
  129. // Seconds-based time units
  130. const (
  131. Minute = 60
  132. Hour = 60 * Minute
  133. Day = 24 * Hour
  134. Week = 7 * Day
  135. Month = 30 * Day
  136. Year = 12 * Month
  137. )
  138. func computeTimeDiff(diff int64) (int64, string) {
  139. diffStr := ""
  140. switch {
  141. case diff <= 0:
  142. diff = 0
  143. diffStr = "now"
  144. case diff < 2:
  145. diff = 0
  146. diffStr = "1 second"
  147. case diff < 1*Minute:
  148. diffStr = fmt.Sprintf("%d seconds", diff)
  149. diff = 0
  150. case diff < 2*Minute:
  151. diff -= 1 * Minute
  152. diffStr = "1 minute"
  153. case diff < 1*Hour:
  154. diffStr = fmt.Sprintf("%d minutes", diff/Minute)
  155. diff -= diff / Minute * Minute
  156. case diff < 2*Hour:
  157. diff -= 1 * Hour
  158. diffStr = "1 hour"
  159. case diff < 1*Day:
  160. diffStr = fmt.Sprintf("%d hours", diff/Hour)
  161. diff -= diff / Hour * Hour
  162. case diff < 2*Day:
  163. diff -= 1 * Day
  164. diffStr = "1 day"
  165. case diff < 1*Week:
  166. diffStr = fmt.Sprintf("%d days", diff/Day)
  167. diff -= diff / Day * Day
  168. case diff < 2*Week:
  169. diff -= 1 * Week
  170. diffStr = "1 week"
  171. case diff < 1*Month:
  172. diffStr = fmt.Sprintf("%d weeks", diff/Week)
  173. diff -= diff / Week * Week
  174. case diff < 2*Month:
  175. diff -= 1 * Month
  176. diffStr = "1 month"
  177. case diff < 1*Year:
  178. diffStr = fmt.Sprintf("%d months", diff/Month)
  179. diff -= diff / Month * Month
  180. case diff < 2*Year:
  181. diff -= 1 * Year
  182. diffStr = "1 year"
  183. default:
  184. diffStr = fmt.Sprintf("%d years", diff/Year)
  185. diff = 0
  186. }
  187. return diff, diffStr
  188. }
  189. // TimeSincePro calculates the time interval and generate full user-friendly string.
  190. func TimeSincePro(then time.Time) string {
  191. now := time.Now()
  192. diff := now.Unix() - then.Unix()
  193. if then.After(now) {
  194. return "future"
  195. }
  196. var timeStr, diffStr string
  197. for {
  198. if diff == 0 {
  199. break
  200. }
  201. diff, diffStr = computeTimeDiff(diff)
  202. timeStr += ", " + diffStr
  203. }
  204. return strings.TrimPrefix(timeStr, ", ")
  205. }
  206. // TimeSince calculates the time interval and generate user-friendly string.
  207. func TimeSince(then time.Time) string {
  208. now := time.Now()
  209. lbl := "ago"
  210. diff := now.Unix() - then.Unix()
  211. if then.After(now) {
  212. lbl = "from now"
  213. diff = then.Unix() - now.Unix()
  214. }
  215. switch {
  216. case diff <= 0:
  217. return "now"
  218. case diff <= 2:
  219. return fmt.Sprintf("1 second %s", lbl)
  220. case diff < 1*Minute:
  221. return fmt.Sprintf("%d seconds %s", diff, lbl)
  222. case diff < 2*Minute:
  223. return fmt.Sprintf("1 minute %s", lbl)
  224. case diff < 1*Hour:
  225. return fmt.Sprintf("%d minutes %s", diff/Minute, lbl)
  226. case diff < 2*Hour:
  227. return fmt.Sprintf("1 hour %s", lbl)
  228. case diff < 1*Day:
  229. return fmt.Sprintf("%d hours %s", diff/Hour, lbl)
  230. case diff < 2*Day:
  231. return fmt.Sprintf("1 day %s", lbl)
  232. case diff < 1*Week:
  233. return fmt.Sprintf("%d days %s", diff/Day, lbl)
  234. case diff < 2*Week:
  235. return fmt.Sprintf("1 week %s", lbl)
  236. case diff < 1*Month:
  237. return fmt.Sprintf("%d weeks %s", diff/Week, lbl)
  238. case diff < 2*Month:
  239. return fmt.Sprintf("1 month %s", lbl)
  240. case diff < 1*Year:
  241. return fmt.Sprintf("%d months %s", diff/Month, lbl)
  242. case diff < 2*Year:
  243. return fmt.Sprintf("1 year %s", lbl)
  244. default:
  245. return fmt.Sprintf("%d years %s", diff/Year, lbl)
  246. }
  247. }
  248. const (
  249. Byte = 1
  250. KByte = Byte * 1024
  251. MByte = KByte * 1024
  252. GByte = MByte * 1024
  253. TByte = GByte * 1024
  254. PByte = TByte * 1024
  255. EByte = PByte * 1024
  256. )
  257. var bytesSizeTable = map[string]uint64{
  258. "b": Byte,
  259. "kb": KByte,
  260. "mb": MByte,
  261. "gb": GByte,
  262. "tb": TByte,
  263. "pb": PByte,
  264. "eb": EByte,
  265. }
  266. func logn(n, b float64) float64 {
  267. return math.Log(n) / math.Log(b)
  268. }
  269. func humanateBytes(s uint64, base float64, sizes []string) string {
  270. if s < 10 {
  271. return fmt.Sprintf("%dB", s)
  272. }
  273. e := math.Floor(logn(float64(s), base))
  274. suffix := sizes[int(e)]
  275. val := float64(s) / math.Pow(base, math.Floor(e))
  276. f := "%.0f"
  277. if val < 10 {
  278. f = "%.1f"
  279. }
  280. return fmt.Sprintf(f+"%s", val, suffix)
  281. }
  282. // FileSize calculates the file size and generate user-friendly string.
  283. func FileSize(s int64) string {
  284. sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"}
  285. return humanateBytes(uint64(s), 1024, sizes)
  286. }
  287. // Subtract deals with subtraction of all types of number.
  288. func Subtract(left interface{}, right interface{}) interface{} {
  289. var rleft, rright int64
  290. var fleft, fright float64
  291. var isInt bool = true
  292. switch left.(type) {
  293. case int:
  294. rleft = int64(left.(int))
  295. case int8:
  296. rleft = int64(left.(int8))
  297. case int16:
  298. rleft = int64(left.(int16))
  299. case int32:
  300. rleft = int64(left.(int32))
  301. case int64:
  302. rleft = left.(int64)
  303. case float32:
  304. fleft = float64(left.(float32))
  305. isInt = false
  306. case float64:
  307. fleft = left.(float64)
  308. isInt = false
  309. }
  310. switch right.(type) {
  311. case int:
  312. rright = int64(right.(int))
  313. case int8:
  314. rright = int64(right.(int8))
  315. case int16:
  316. rright = int64(right.(int16))
  317. case int32:
  318. rright = int64(right.(int32))
  319. case int64:
  320. rright = right.(int64)
  321. case float32:
  322. fright = float64(left.(float32))
  323. isInt = false
  324. case float64:
  325. fleft = left.(float64)
  326. isInt = false
  327. }
  328. if isInt {
  329. return rleft - rright
  330. } else {
  331. return fleft + float64(rleft) - (fright + float64(rright))
  332. }
  333. }
  334. // DateFormat pattern rules.
  335. var datePatterns = []string{
  336. // year
  337. "Y", "2006", // A full numeric representation of a year, 4 digits Examples: 1999 or 2003
  338. "y", "06", //A two digit representation of a year Examples: 99 or 03
  339. // month
  340. "m", "01", // Numeric representation of a month, with leading zeros 01 through 12
  341. "n", "1", // Numeric representation of a month, without leading zeros 1 through 12
  342. "M", "Jan", // A short textual representation of a month, three letters Jan through Dec
  343. "F", "January", // A full textual representation of a month, such as January or March January through December
  344. // day
  345. "d", "02", // Day of the month, 2 digits with leading zeros 01 to 31
  346. "j", "2", // Day of the month without leading zeros 1 to 31
  347. // week
  348. "D", "Mon", // A textual representation of a day, three letters Mon through Sun
  349. "l", "Monday", // A full textual representation of the day of the week Sunday through Saturday
  350. // time
  351. "g", "3", // 12-hour format of an hour without leading zeros 1 through 12
  352. "G", "15", // 24-hour format of an hour without leading zeros 0 through 23
  353. "h", "03", // 12-hour format of an hour with leading zeros 01 through 12
  354. "H", "15", // 24-hour format of an hour with leading zeros 00 through 23
  355. "a", "pm", // Lowercase Ante meridiem and Post meridiem am or pm
  356. "A", "PM", // Uppercase Ante meridiem and Post meridiem AM or PM
  357. "i", "04", // Minutes with leading zeros 00 to 59
  358. "s", "05", // Seconds, with leading zeros 00 through 59
  359. // time zone
  360. "T", "MST",
  361. "P", "-07:00",
  362. "O", "-0700",
  363. // RFC 2822
  364. "r", time.RFC1123Z,
  365. }
  366. // Parse Date use PHP time format.
  367. func DateParse(dateString, format string) (time.Time, error) {
  368. replacer := strings.NewReplacer(datePatterns...)
  369. format = replacer.Replace(format)
  370. return time.ParseInLocation(format, dateString, time.Local)
  371. }
  372. // Date takes a PHP like date func to Go's time format.
  373. func DateFormat(t time.Time, format string) string {
  374. replacer := strings.NewReplacer(datePatterns...)
  375. format = replacer.Replace(format)
  376. return t.Format(format)
  377. }
  378. // convert string to specify type
  379. type StrTo string
  380. func (f StrTo) Exist() bool {
  381. return string(f) != string(0x1E)
  382. }
  383. func (f StrTo) Int() (int, error) {
  384. v, err := strconv.ParseInt(f.String(), 10, 32)
  385. return int(v), err
  386. }
  387. func (f StrTo) Int64() (int64, error) {
  388. v, err := strconv.ParseInt(f.String(), 10, 64)
  389. return int64(v), err
  390. }
  391. func (f StrTo) String() string {
  392. if f.Exist() {
  393. return string(f)
  394. }
  395. return ""
  396. }
  397. // convert any type to string
  398. func ToStr(value interface{}, args ...int) (s string) {
  399. switch v := value.(type) {
  400. case bool:
  401. s = strconv.FormatBool(v)
  402. case float32:
  403. s = strconv.FormatFloat(float64(v), 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 32))
  404. case float64:
  405. s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64))
  406. case int:
  407. s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
  408. case int8:
  409. s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
  410. case int16:
  411. s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
  412. case int32:
  413. s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
  414. case int64:
  415. s = strconv.FormatInt(v, argInt(args).Get(0, 10))
  416. case uint:
  417. s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
  418. case uint8:
  419. s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
  420. case uint16:
  421. s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
  422. case uint32:
  423. s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
  424. case uint64:
  425. s = strconv.FormatUint(v, argInt(args).Get(0, 10))
  426. case string:
  427. s = v
  428. case []byte:
  429. s = string(v)
  430. default:
  431. s = fmt.Sprintf("%v", v)
  432. }
  433. return s
  434. }
  435. type argInt []int
  436. func (a argInt) Get(i int, args ...int) (r int) {
  437. if i >= 0 && i < len(a) {
  438. r = a[i]
  439. }
  440. if len(args) > 0 {
  441. r = args[0]
  442. }
  443. return
  444. }