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.

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