Files
2023-02-14 14:55:35 -08:00

75 lines
1.9 KiB
Go

/******************************************************************************
*
* Description :
*
* Authentication
*
*****************************************************************************/
package main
import (
"bytes"
"crypto/hmac"
"crypto/md5"
"encoding/base64"
"github.com/tinode/chat/server/logs"
)
// Singned AppID. Composition:
//
// [1:algorithm version][4:appid][2:key sequence][1:isRoot][16:signature] = 24 bytes
//
// convertible to base64 without padding. All integers are little-endian.
// Definitions for byte lengths of key's parts.
const (
// apikeyVersion is the version of this API scheme.
apikeyVersion = 1
// apikeyAppID is deprecated and will be removed in the future.
apikeyAppID = 4
// apikeySequence is the serial number of the key.
apikeySequence = 2
// apikeyWho indicates if the key grants root privileges.
apikeyWho = 1
// apikeySignature is key's cryptographic (HMAC) signature.
apikeySignature = 16
// apikeyLength is the length of the key in bytes.
apikeyLength = apikeyVersion + apikeyAppID + apikeySequence + apikeyWho + apikeySignature
)
// Client signature validation
//
// key: client's secret key
//
// Returns application id, key type.
func checkAPIKey(apikey string) (isValid, isRoot bool) {
if declen := base64.URLEncoding.DecodedLen(len(apikey)); declen != apikeyLength {
return
}
data, err := base64.URLEncoding.DecodeString(apikey)
if err != nil {
logs.Warn.Println("failed to decode.base64 appid ", err)
return
}
if data[0] != 1 {
logs.Warn.Println("unknown appid signature algorithm ", data[0])
return
}
hasher := hmac.New(md5.New, globals.apiKeySalt)
hasher.Write(data[:apikeyVersion+apikeyAppID+apikeySequence+apikeyWho])
check := hasher.Sum(nil)
if !bytes.Equal(data[apikeyVersion+apikeyAppID+apikeySequence+apikeyWho:], check) {
logs.Warn.Println("invalid apikey signature")
return
}
isRoot = (data[apikeyVersion+apikeyAppID+apikeySequence] == 1)
isValid = true
return
}