2014-02-18 17:31:16 -05:00
// Copyright 2014 The Gogs Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2014-02-18 17:31:16 -05:00
2014-03-07 17:22:15 -05:00
package base
2014-02-18 17:31:16 -05:00
import (
2024-05-20 23:12:50 +08:00
"crypto/hmac"
2014-03-19 07:21:23 -04:00
"crypto/sha1"
2024-02-25 14:32:13 +01:00
"crypto/sha256"
2024-05-20 23:12:50 +08:00
"crypto/subtle"
2014-11-07 14:46:13 -05:00
"encoding/base64"
2014-02-18 17:31:16 -05:00
"encoding/hex"
2020-12-18 02:51:28 +01:00
"errors"
2014-03-14 02:32:11 -04:00
"fmt"
2024-05-20 23:12:50 +08:00
"hash"
2016-11-07 21:49:50 +01:00
"strconv"
2014-03-15 15:28:06 +08:00
"strings"
2014-03-14 02:32:11 -04:00
"time"
2014-05-25 20:11:25 -04:00
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/modules/setting"
2024-12-26 11:56:03 +08:00
"code.gitea.io/gitea/modules/util"
2019-03-27 17:33:00 +08:00
2020-02-03 21:50:37 +02:00
"github.com/dustin/go-humanize"
2014-02-18 17:31:16 -05:00
)
2022-11-26 17:21:54 +01:00
// EncodeSha256 string to sha256 hex value.
2019-05-04 11:45:34 -04:00
func EncodeSha256 ( str string ) string {
h := sha256 . New ( )
2019-06-12 21:41:28 +02:00
_ , _ = h . Write ( [ ] byte ( str ) )
2019-05-04 11:45:34 -04:00
return hex . EncodeToString ( h . Sum ( nil ) )
}
2016-11-07 23:14:50 +01:00
// ShortSha is basically just truncating.
// It is DEPRECATED and will be removed in the future.
2015-11-13 17:10:25 -05:00
func ShortSha ( sha1 string ) string {
2024-12-26 11:56:03 +08:00
return util . TruncateRunes ( sha1 , 10 )
2015-11-13 17:10:25 -05:00
}
2016-11-24 15:17:44 +08:00
// BasicAuthDecode decode basic auth string
2014-12-10 05:10:26 -05:00
func BasicAuthDecode ( encoded string ) ( string , string , error ) {
s , err := base64 . StdEncoding . DecodeString ( encoded )
2014-11-07 14:46:13 -05:00
if err != nil {
2014-12-10 05:10:26 -05:00
return "" , "" , err
2014-11-07 14:46:13 -05:00
}
2024-07-23 14:43:03 +02:00
if username , password , ok := strings . Cut ( string ( s ) , ":" ) ; ok {
return username , password , nil
2020-12-18 02:51:28 +01:00
}
2024-07-23 14:43:03 +02:00
return "" , "" , errors . New ( "invalid basic authentication" )
2014-11-07 14:46:13 -05:00
}
2016-11-24 15:17:44 +08:00
// VerifyTimeLimitCode verify time limit code
2024-05-20 23:12:50 +08:00
func VerifyTimeLimitCode ( now time . Time , data string , minutes int , code string ) bool {
2014-03-19 12:50:44 -04:00
if len ( code ) <= 18 {
return false
}
2024-05-20 23:12:50 +08:00
startTimeStr := code [ : 12 ]
aliveTimeStr := code [ 12 : 18 ]
aliveTime , _ := strconv . Atoi ( aliveTimeStr ) // no need to check err, if anything wrong, the following code check will fail soon
2014-03-19 12:50:44 -04:00
2024-05-20 23:12:50 +08:00
// check code
retCode := CreateTimeLimitCode ( data , aliveTime , startTimeStr , nil )
if subtle . ConstantTimeCompare ( [ ] byte ( retCode ) , [ ] byte ( code ) ) != 1 {
2025-02-03 02:16:56 +08:00
return false
2014-03-19 12:50:44 -04:00
}
2024-05-20 23:12:50 +08:00
// check time is expired or not: startTime <= now && now < startTime + minutes
startTime , _ := time . ParseInLocation ( "200601021504" , startTimeStr , time . Local )
return ( startTime . Before ( now ) || startTime . Equal ( now ) ) && now . Before ( startTime . Add ( time . Minute * time . Duration ( minutes ) ) )
2014-03-19 12:50:44 -04:00
}
2016-11-24 15:17:44 +08:00
// TimeLimitCodeLength default value for time limit code
2014-03-19 12:50:44 -04:00
const TimeLimitCodeLength = 12 + 6 + 40
2024-05-20 23:12:50 +08:00
// CreateTimeLimitCode create a time-limited code.
// Format: 12 length date time string + 6 minutes string (not used) + 40 hash string, some other code depends on this fixed length
// If h is nil, then use the default hmac hash.
func CreateTimeLimitCode [ T time . Time | string ] ( data string , minutes int , startTimeGeneric T , h hash . Hash ) string {
const format = "200601021504"
2014-03-19 07:21:23 -04:00
2024-05-20 23:12:50 +08:00
var start time . Time
var startTimeAny any = startTimeGeneric
if t , ok := startTimeAny . ( time . Time ) ; ok {
start = t
2014-03-19 07:21:23 -04:00
} else {
2024-05-20 23:12:50 +08:00
var err error
start , err = time . ParseInLocation ( format , startTimeAny . ( string ) , time . Local )
if err != nil {
return "" // return an invalid code because the "parse" failed
}
2014-03-19 07:21:23 -04:00
}
2024-05-20 23:12:50 +08:00
startStr := start . Format ( format )
end := start . Add ( time . Minute * time . Duration ( minutes ) )
2014-03-19 07:21:23 -04:00
2024-05-20 23:12:50 +08:00
if h == nil {
h = hmac . New ( sha1 . New , setting . GetGeneralTokenSigningSecret ( ) )
}
_ , _ = fmt . Fprintf ( h , "%s%s%s%s%d" , data , hex . EncodeToString ( setting . GetGeneralTokenSigningSecret ( ) ) , startStr , end . Format ( format ) , minutes )
encoded := hex . EncodeToString ( h . Sum ( nil ) )
2014-03-19 07:21:23 -04:00
code := fmt . Sprintf ( "%s%06d%s" , startStr , minutes , encoded )
2024-05-20 23:12:50 +08:00
if len ( code ) != TimeLimitCodeLength {
panic ( "there is a hard requirement for the length of time-limited code" ) // it shouldn't happen
}
2014-03-19 07:21:23 -04:00
return code
}
2014-03-15 12:29:49 -04:00
// FileSize calculates the file size and generate user-friendly string.
2014-03-15 12:31:12 -04:00
func FileSize ( s int64 ) string {
2020-02-03 21:50:37 +02:00
return humanize . IBytes ( uint64 ( s ) )
}
2015-08-10 16:52:08 +08:00
// StringsToInt64s converts a slice of string to a slice of int64.
2016-12-22 03:58:04 -05:00
func StringsToInt64s ( strs [ ] string ) ( [ ] int64 , error ) {
2024-03-21 23:07:35 +08:00
if strs == nil {
return nil , nil
}
ints := make ( [ ] int64 , 0 , len ( strs ) )
for _ , s := range strs {
2024-11-11 04:07:54 +08:00
if s == "" {
continue
}
2024-03-21 23:07:35 +08:00
n , err := strconv . ParseInt ( s , 10 , 64 )
2016-12-22 03:58:04 -05:00
if err != nil {
2024-03-21 23:07:35 +08:00
return nil , err
2016-12-22 03:58:04 -05:00
}
2024-03-21 23:07:35 +08:00
ints = append ( ints , n )
2015-08-10 16:52:08 +08:00
}
2016-12-22 03:58:04 -05:00
return ints , nil
2015-08-10 16:52:08 +08:00
}
2015-08-25 23:22:05 +08:00
// Int64sToStrings converts a slice of int64 to a slice of string.
func Int64sToStrings ( ints [ ] int64 ) [ ] string {
strs := make ( [ ] string , len ( ints ) )
for i := range ints {
2016-11-07 21:49:50 +01:00
strs [ i ] = strconv . FormatInt ( ints [ i ] , 10 )
2015-08-25 23:22:05 +08:00
}
return strs
}