Permit using unhashed tokens for routes

While only a few routes implement this - such as SyncRegistration - we do not mind heavily if another client developed by a third party utilizes routes with only hashed/unhashed tokens.
This commit is contained in:
Spotlight 2022-01-09 03:33:08 -06:00
parent d7af36a6c8
commit 97ce2212c6
No known key found for this signature in database
GPG Key ID: 874AA355B3209BDC
2 changed files with 45 additions and 15 deletions

View File

@ -42,3 +42,13 @@ const (
DeviceStatusRegistered = "R" DeviceStatusRegistered = "R"
DeviceStatusUnregistered = "U" DeviceStatusUnregistered = "U"
) )
// TokenType represents a way to distinguish between ST- (unhashed)
// and WT- (hashed) device tokens.
type TokenType int
const (
TokenTypeUnhashed = iota
TokenTypeHashed
TokenTypeInvalid
)

View File

@ -145,7 +145,8 @@ func (route *Route) Handle() http.Handler {
} }
const ( const (
RouteVerifyStatement = `SELECT device_id FROM userbase WHERE device_token_hashed=$1 AND account_id=$2 AND device_id=$3` RouteVerifyHashedStatement = `SELECT 1 FROM userbase WHERE device_token_hashed=$1 AND account_id=$2 AND device_id=$3`
RouteVerifyUnhashedStatement = `SELECT 1 FROM userbase WHERE device_token=$1 AND account_id=$2 AND device_id=$3`
) )
// checkAuthentication validates various factors from a given request requiring authentication. // checkAuthentication validates various factors from a given request requiring authentication.
@ -164,13 +165,20 @@ func checkAuthentication(e *Envelope) (bool, error) {
return false, err return false, err
} }
hash := validateTokenFormat(deviceToken) hash, tokenType := determineTokenFormat(deviceToken)
if hash == "" { if hash == "" || tokenType == TokenTypeInvalid {
return false, nil return false, nil
} }
var statement string
if tokenType == TokenTypeHashed {
statement = RouteVerifyHashedStatement
} else if tokenType == TokenTypeUnhashed {
statement = RouteVerifyUnhashedStatement
}
// Check using various input given. // Check using various input given.
row := pool.QueryRow(ctx, RouteVerifyStatement, hash, accountId, e.DeviceId()) row := pool.QueryRow(ctx, statement, hash, accountId, e.DeviceId())
var throwaway int var throwaway int
err = row.Scan(&throwaway) err = row.Scan(&throwaway)
@ -185,18 +193,30 @@ func checkAuthentication(e *Envelope) (bool, error) {
} }
} }
// validateTokenFormat confirms the prefix and size of tokens, // validateTokenFormat confirms the prefix, size and type of tokens,
// in a format such as WT-5d41402abc4b2a76b9719d911017c592. // which are expected to be in a format such as
// It returns an empty string on failure. // WT-5d41402abc4b2a76b9719d911017c592 or ST-aech1kae4sheequ8Zohwa.
func validateTokenFormat(token string) string { // It returns an empty string on failure, alongside TokenTypeInvalid.
success := len(token) == 35 && token[:3] == "WT-" func determineTokenFormat(token string) (string, TokenType) {
tokenLen := len(token)
if success { if tokenLen < 3 {
// Strips the WT- prefix off. return "", TokenTypeInvalid
return token[3:35]
} else {
return ""
} }
switch token[:3] {
case "ST-":
// Unhashed tokens are 24 characters in length.
if tokenLen == 24 {
return token[3:24], TokenTypeUnhashed
}
case "WT-":
// Hashed tokens are 45 characters in length.
if tokenLen == 45 {
return token[3:45], TokenTypeHashed
}
}
return "", TokenTypeInvalid
} }
func printError(w http.ResponseWriter, reason string) { func printError(w http.ResponseWriter, reason string) {