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

515 lines
12 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  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 DisableGravatar {
  125. return "/img/avatar_default.jpg"
  126. } else if Service.EnableCacheAvatar {
  127. return "/avatar/" + EncodeMd5(email)
  128. }
  129. return "//1.gravatar.com/avatar/" + EncodeMd5(email)
  130. }
  131. // Seconds-based time units
  132. const (
  133. Minute = 60
  134. Hour = 60 * Minute
  135. Day = 24 * Hour
  136. Week = 7 * Day
  137. Month = 30 * Day
  138. Year = 12 * Month
  139. )
  140. func computeTimeDiff(diff int64) (int64, string) {
  141. diffStr := ""
  142. switch {
  143. case diff <= 0:
  144. diff = 0
  145. diffStr = "now"
  146. case diff < 2:
  147. diff = 0
  148. diffStr = "1 second"
  149. case diff < 1*Minute:
  150. diffStr = fmt.Sprintf("%d seconds", diff)
  151. diff = 0
  152. case diff < 2*Minute:
  153. diff -= 1 * Minute
  154. diffStr = "1 minute"
  155. case diff < 1*Hour:
  156. diffStr = fmt.Sprintf("%d minutes", diff/Minute)
  157. diff -= diff / Minute * Minute
  158. case diff < 2*Hour:
  159. diff -= 1 * Hour
  160. diffStr = "1 hour"
  161. case diff < 1*Day:
  162. diffStr = fmt.Sprintf("%d hours", diff/Hour)
  163. diff -= diff / Hour * Hour
  164. case diff < 2*Day:
  165. diff -= 1 * Day
  166. diffStr = "1 day"
  167. case diff < 1*Week:
  168. diffStr = fmt.Sprintf("%d days", diff/Day)
  169. diff -= diff / Day * Day
  170. case diff < 2*Week:
  171. diff -= 1 * Week
  172. diffStr = "1 week"
  173. case diff < 1*Month:
  174. diffStr = fmt.Sprintf("%d weeks", diff/Week)
  175. diff -= diff / Week * Week
  176. case diff < 2*Month:
  177. diff -= 1 * Month
  178. diffStr = "1 month"
  179. case diff < 1*Year:
  180. diffStr = fmt.Sprintf("%d months", diff/Month)
  181. diff -= diff / Month * Month
  182. case diff < 2*Year:
  183. diff -= 1 * Year
  184. diffStr = "1 year"
  185. default:
  186. diffStr = fmt.Sprintf("%d years", diff/Year)
  187. diff = 0
  188. }
  189. return diff, diffStr
  190. }
  191. // TimeSincePro calculates the time interval and generate full user-friendly string.
  192. func TimeSincePro(then time.Time) string {
  193. now := time.Now()
  194. diff := now.Unix() - then.Unix()
  195. if then.After(now) {
  196. return "future"
  197. }
  198. var timeStr, diffStr string
  199. for {
  200. if diff == 0 {
  201. break
  202. }
  203. diff, diffStr = computeTimeDiff(diff)
  204. timeStr += ", " + diffStr
  205. }
  206. return strings.TrimPrefix(timeStr, ", ")
  207. }
  208. // TimeSince calculates the time interval and generate user-friendly string.
  209. func TimeSince(then time.Time) string {
  210. now := time.Now()
  211. lbl := "ago"
  212. diff := now.Unix() - then.Unix()
  213. if then.After(now) {
  214. lbl = "from now"
  215. diff = then.Unix() - now.Unix()
  216. }
  217. switch {
  218. case diff <= 0:
  219. return "now"
  220. case diff <= 2:
  221. return fmt.Sprintf("1 second %s", lbl)
  222. case diff < 1*Minute:
  223. return fmt.Sprintf("%d seconds %s", diff, lbl)
  224. case diff < 2*Minute:
  225. return fmt.Sprintf("1 minute %s", lbl)
  226. case diff < 1*Hour:
  227. return fmt.Sprintf("%d minutes %s", diff/Minute, lbl)
  228. case diff < 2*Hour:
  229. return fmt.Sprintf("1 hour %s", lbl)
  230. case diff < 1*Day:
  231. return fmt.Sprintf("%d hours %s", diff/Hour, lbl)
  232. case diff < 2*Day:
  233. return fmt.Sprintf("1 day %s", lbl)
  234. case diff < 1*Week:
  235. return fmt.Sprintf("%d days %s", diff/Day, lbl)
  236. case diff < 2*Week:
  237. return fmt.Sprintf("1 week %s", lbl)
  238. case diff < 1*Month:
  239. return fmt.Sprintf("%d weeks %s", diff/Week, lbl)
  240. case diff < 2*Month:
  241. return fmt.Sprintf("1 month %s", lbl)
  242. case diff < 1*Year:
  243. return fmt.Sprintf("%d months %s", diff/Month, lbl)
  244. case diff < 2*Year:
  245. return fmt.Sprintf("1 year %s", lbl)
  246. default:
  247. return fmt.Sprintf("%d years %s", diff/Year, lbl)
  248. }
  249. }
  250. const (
  251. Byte = 1
  252. KByte = Byte * 1024
  253. MByte = KByte * 1024
  254. GByte = MByte * 1024
  255. TByte = GByte * 1024
  256. PByte = TByte * 1024
  257. EByte = PByte * 1024
  258. )
  259. var bytesSizeTable = map[string]uint64{
  260. "b": Byte,
  261. "kb": KByte,
  262. "mb": MByte,
  263. "gb": GByte,
  264. "tb": TByte,
  265. "pb": PByte,
  266. "eb": EByte,
  267. }
  268. func logn(n, b float64) float64 {
  269. return math.Log(n) / math.Log(b)
  270. }
  271. func humanateBytes(s uint64, base float64, sizes []string) string {
  272. if s < 10 {
  273. return fmt.Sprintf("%dB", s)
  274. }
  275. e := math.Floor(logn(float64(s), base))
  276. suffix := sizes[int(e)]
  277. val := float64(s) / math.Pow(base, math.Floor(e))
  278. f := "%.0f"
  279. if val < 10 {
  280. f = "%.1f"
  281. }
  282. return fmt.Sprintf(f+"%s", val, suffix)
  283. }
  284. // FileSize calculates the file size and generate user-friendly string.
  285. func FileSize(s int64) string {
  286. sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"}
  287. return humanateBytes(uint64(s), 1024, sizes)
  288. }
  289. // Subtract deals with subtraction of all types of number.
  290. func Subtract(left interface{}, right interface{}) interface{} {
  291. var rleft, rright int64
  292. var fleft, fright float64
  293. var isInt bool = true
  294. switch left.(type) {
  295. case int:
  296. rleft = int64(left.(int))
  297. case int8:
  298. rleft = int64(left.(int8))
  299. case int16:
  300. rleft = int64(left.(int16))
  301. case int32:
  302. rleft = int64(left.(int32))
  303. case int64:
  304. rleft = left.(int64)
  305. case float32:
  306. fleft = float64(left.(float32))
  307. isInt = false
  308. case float64:
  309. fleft = left.(float64)
  310. isInt = false
  311. }
  312. switch right.(type) {
  313. case int:
  314. rright = int64(right.(int))
  315. case int8:
  316. rright = int64(right.(int8))
  317. case int16:
  318. rright = int64(right.(int16))
  319. case int32:
  320. rright = int64(right.(int32))
  321. case int64:
  322. rright = right.(int64)
  323. case float32:
  324. fright = float64(left.(float32))
  325. isInt = false
  326. case float64:
  327. fleft = left.(float64)
  328. isInt = false
  329. }
  330. if isInt {
  331. return rleft - rright
  332. } else {
  333. return fleft + float64(rleft) - (fright + float64(rright))
  334. }
  335. }
  336. // DateFormat pattern rules.
  337. var datePatterns = []string{
  338. // year
  339. "Y", "2006", // A full numeric representation of a year, 4 digits Examples: 1999 or 2003
  340. "y", "06", //A two digit representation of a year Examples: 99 or 03
  341. // month
  342. "m", "01", // Numeric representation of a month, with leading zeros 01 through 12
  343. "n", "1", // Numeric representation of a month, without leading zeros 1 through 12
  344. "M", "Jan", // A short textual representation of a month, three letters Jan through Dec
  345. "F", "January", // A full textual representation of a month, such as January or March January through December
  346. // day
  347. "d", "02", // Day of the month, 2 digits with leading zeros 01 to 31
  348. "j", "2", // Day of the month without leading zeros 1 to 31
  349. // week
  350. "D", "Mon", // A textual representation of a day, three letters Mon through Sun
  351. "l", "Monday", // A full textual representation of the day of the week Sunday through Saturday
  352. // time
  353. "g", "3", // 12-hour format of an hour without leading zeros 1 through 12
  354. "G", "15", // 24-hour format of an hour without leading zeros 0 through 23
  355. "h", "03", // 12-hour format of an hour with leading zeros 01 through 12
  356. "H", "15", // 24-hour format of an hour with leading zeros 00 through 23
  357. "a", "pm", // Lowercase Ante meridiem and Post meridiem am or pm
  358. "A", "PM", // Uppercase Ante meridiem and Post meridiem AM or PM
  359. "i", "04", // Minutes with leading zeros 00 to 59
  360. "s", "05", // Seconds, with leading zeros 00 through 59
  361. // time zone
  362. "T", "MST",
  363. "P", "-07:00",
  364. "O", "-0700",
  365. // RFC 2822
  366. "r", time.RFC1123Z,
  367. }
  368. // Parse Date use PHP time format.
  369. func DateParse(dateString, format string) (time.Time, error) {
  370. replacer := strings.NewReplacer(datePatterns...)
  371. format = replacer.Replace(format)
  372. return time.ParseInLocation(format, dateString, time.Local)
  373. }
  374. // Date takes a PHP like date func to Go's time format.
  375. func DateFormat(t time.Time, format string) string {
  376. replacer := strings.NewReplacer(datePatterns...)
  377. format = replacer.Replace(format)
  378. return t.Format(format)
  379. }
  380. // convert string to specify type
  381. type StrTo string
  382. func (f StrTo) Exist() bool {
  383. return string(f) != string(0x1E)
  384. }
  385. func (f StrTo) Int() (int, error) {
  386. v, err := strconv.ParseInt(f.String(), 10, 32)
  387. return int(v), err
  388. }
  389. func (f StrTo) Int64() (int64, error) {
  390. v, err := strconv.ParseInt(f.String(), 10, 64)
  391. return int64(v), err
  392. }
  393. func (f StrTo) String() string {
  394. if f.Exist() {
  395. return string(f)
  396. }
  397. return ""
  398. }
  399. // convert any type to string
  400. func ToStr(value interface{}, args ...int) (s string) {
  401. switch v := value.(type) {
  402. case bool:
  403. s = strconv.FormatBool(v)
  404. case float32:
  405. s = strconv.FormatFloat(float64(v), 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 32))
  406. case float64:
  407. s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64))
  408. case int:
  409. s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
  410. case int8:
  411. s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
  412. case int16:
  413. s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
  414. case int32:
  415. s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
  416. case int64:
  417. s = strconv.FormatInt(v, argInt(args).Get(0, 10))
  418. case uint:
  419. s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
  420. case uint8:
  421. s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
  422. case uint16:
  423. s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
  424. case uint32:
  425. s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
  426. case uint64:
  427. s = strconv.FormatUint(v, argInt(args).Get(0, 10))
  428. case string:
  429. s = v
  430. case []byte:
  431. s = string(v)
  432. default:
  433. s = fmt.Sprintf("%v", v)
  434. }
  435. return s
  436. }
  437. type argInt []int
  438. func (a argInt) Get(i int, args ...int) (r int) {
  439. if i >= 0 && i < len(a) {
  440. r = a[i]
  441. }
  442. if len(args) > 0 {
  443. r = args[0]
  444. }
  445. return
  446. }