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.

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