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.

514 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
  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 "http://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. return then.String()
  248. }
  249. const (
  250. Byte = 1
  251. KByte = Byte * 1024
  252. MByte = KByte * 1024
  253. GByte = MByte * 1024
  254. TByte = GByte * 1024
  255. PByte = TByte * 1024
  256. EByte = PByte * 1024
  257. )
  258. var bytesSizeTable = map[string]uint64{
  259. "b": Byte,
  260. "kb": KByte,
  261. "mb": MByte,
  262. "gb": GByte,
  263. "tb": TByte,
  264. "pb": PByte,
  265. "eb": EByte,
  266. }
  267. func logn(n, b float64) float64 {
  268. return math.Log(n) / math.Log(b)
  269. }
  270. func humanateBytes(s uint64, base float64, sizes []string) string {
  271. if s < 10 {
  272. return fmt.Sprintf("%dB", s)
  273. }
  274. e := math.Floor(logn(float64(s), base))
  275. suffix := sizes[int(e)]
  276. val := float64(s) / math.Pow(base, math.Floor(e))
  277. f := "%.0f"
  278. if val < 10 {
  279. f = "%.1f"
  280. }
  281. return fmt.Sprintf(f+"%s", val, suffix)
  282. }
  283. // FileSize calculates the file size and generate user-friendly string.
  284. func FileSize(s int64) string {
  285. sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"}
  286. return humanateBytes(uint64(s), 1024, sizes)
  287. }
  288. // Subtract deals with subtraction of all types of number.
  289. func Subtract(left interface{}, right interface{}) interface{} {
  290. var rleft, rright int64
  291. var fleft, fright float64
  292. var isInt bool = true
  293. switch left.(type) {
  294. case int:
  295. rleft = int64(left.(int))
  296. case int8:
  297. rleft = int64(left.(int8))
  298. case int16:
  299. rleft = int64(left.(int16))
  300. case int32:
  301. rleft = int64(left.(int32))
  302. case int64:
  303. rleft = left.(int64)
  304. case float32:
  305. fleft = float64(left.(float32))
  306. isInt = false
  307. case float64:
  308. fleft = left.(float64)
  309. isInt = false
  310. }
  311. switch right.(type) {
  312. case int:
  313. rright = int64(right.(int))
  314. case int8:
  315. rright = int64(right.(int8))
  316. case int16:
  317. rright = int64(right.(int16))
  318. case int32:
  319. rright = int64(right.(int32))
  320. case int64:
  321. rright = right.(int64)
  322. case float32:
  323. fright = float64(left.(float32))
  324. isInt = false
  325. case float64:
  326. fleft = left.(float64)
  327. isInt = false
  328. }
  329. if isInt {
  330. return rleft - rright
  331. } else {
  332. return fleft + float64(rleft) - (fright + float64(rright))
  333. }
  334. }
  335. // DateFormat pattern rules.
  336. var datePatterns = []string{
  337. // year
  338. "Y", "2006", // A full numeric representation of a year, 4 digits Examples: 1999 or 2003
  339. "y", "06", //A two digit representation of a year Examples: 99 or 03
  340. // month
  341. "m", "01", // Numeric representation of a month, with leading zeros 01 through 12
  342. "n", "1", // Numeric representation of a month, without leading zeros 1 through 12
  343. "M", "Jan", // A short textual representation of a month, three letters Jan through Dec
  344. "F", "January", // A full textual representation of a month, such as January or March January through December
  345. // day
  346. "d", "02", // Day of the month, 2 digits with leading zeros 01 to 31
  347. "j", "2", // Day of the month without leading zeros 1 to 31
  348. // week
  349. "D", "Mon", // A textual representation of a day, three letters Mon through Sun
  350. "l", "Monday", // A full textual representation of the day of the week Sunday through Saturday
  351. // time
  352. "g", "3", // 12-hour format of an hour without leading zeros 1 through 12
  353. "G", "15", // 24-hour format of an hour without leading zeros 0 through 23
  354. "h", "03", // 12-hour format of an hour with leading zeros 01 through 12
  355. "H", "15", // 24-hour format of an hour with leading zeros 00 through 23
  356. "a", "pm", // Lowercase Ante meridiem and Post meridiem am or pm
  357. "A", "PM", // Uppercase Ante meridiem and Post meridiem AM or PM
  358. "i", "04", // Minutes with leading zeros 00 to 59
  359. "s", "05", // Seconds, with leading zeros 00 through 59
  360. // time zone
  361. "T", "MST",
  362. "P", "-07:00",
  363. "O", "-0700",
  364. // RFC 2822
  365. "r", time.RFC1123Z,
  366. }
  367. // Parse Date use PHP time format.
  368. func DateParse(dateString, format string) (time.Time, error) {
  369. replacer := strings.NewReplacer(datePatterns...)
  370. format = replacer.Replace(format)
  371. return time.ParseInLocation(format, dateString, time.Local)
  372. }
  373. // Date takes a PHP like date func to Go's time format.
  374. func DateFormat(t time.Time, format string) string {
  375. replacer := strings.NewReplacer(datePatterns...)
  376. format = replacer.Replace(format)
  377. return t.Format(format)
  378. }
  379. // convert string to specify type
  380. type StrTo string
  381. func (f StrTo) Exist() bool {
  382. return string(f) != string(0x1E)
  383. }
  384. func (f StrTo) Int() (int, error) {
  385. v, err := strconv.ParseInt(f.String(), 10, 32)
  386. return int(v), err
  387. }
  388. func (f StrTo) Int64() (int64, error) {
  389. v, err := strconv.ParseInt(f.String(), 10, 64)
  390. return int64(v), err
  391. }
  392. func (f StrTo) String() string {
  393. if f.Exist() {
  394. return string(f)
  395. }
  396. return ""
  397. }
  398. // convert any type to string
  399. func ToStr(value interface{}, args ...int) (s string) {
  400. switch v := value.(type) {
  401. case bool:
  402. s = strconv.FormatBool(v)
  403. case float32:
  404. s = strconv.FormatFloat(float64(v), 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 32))
  405. case float64:
  406. s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64))
  407. case int:
  408. s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
  409. case int8:
  410. s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
  411. case int16:
  412. s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
  413. case int32:
  414. s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
  415. case int64:
  416. s = strconv.FormatInt(v, argInt(args).Get(0, 10))
  417. case uint:
  418. s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
  419. case uint8:
  420. s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
  421. case uint16:
  422. s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
  423. case uint32:
  424. s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
  425. case uint64:
  426. s = strconv.FormatUint(v, argInt(args).Get(0, 10))
  427. case string:
  428. s = v
  429. case []byte:
  430. s = string(v)
  431. default:
  432. s = fmt.Sprintf("%v", v)
  433. }
  434. return s
  435. }
  436. type argInt []int
  437. func (a argInt) Get(i int, args ...int) (r int) {
  438. if i >= 0 && i < len(a) {
  439. r = a[i]
  440. }
  441. if len(args) > 0 {
  442. r = args[0]
  443. }
  444. return
  445. }