mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 11:01:44 +00:00
chore: Expose ParsePersonalAccessToken publicly for src-cli (#62587)
This commit is contained in:
parent
e37a78bbd3
commit
3a8666b99a
@ -11,8 +11,7 @@ go_library(
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/hashutil",
|
||||
"//internal/lazyregexp",
|
||||
"//lib/errors",
|
||||
"//lib/accesstoken",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@ -7,8 +7,7 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/internal/lazyregexp"
|
||||
"github.com/sourcegraph/sourcegraph/lib/errors"
|
||||
libaccesstoken "github.com/sourcegraph/sourcegraph/lib/accesstoken"
|
||||
)
|
||||
|
||||
// PersonalAccessTokenPrefix is the token prefix for Sourcegraph personal access tokens. Its purpose
|
||||
@ -19,22 +18,7 @@ const LocalInstanceIdentifier = "local"
|
||||
const InstanceIdentifierLength = 16
|
||||
const InstanceIdentifierHmacKey = "instance_identifier_hmac_key" // Public as we are using HMAC for key derivation, not for authentication
|
||||
|
||||
var personalAccessTokenRegex = lazyregexp.New("^(?:sgp_|sgph_)?(?:[a-fA-F0-9]{16}_|local_)?([a-fA-F0-9]{40})$")
|
||||
|
||||
// ParsePersonalAccessToken parses a personal access token to remove prefixes and extract the <token> that is stored in the database
|
||||
// Personal access tokens can take several forms:
|
||||
// - <token>
|
||||
// - sgp_<token>
|
||||
// - sgp_<instance-identifier>_<token>
|
||||
func ParsePersonalAccessToken(token string) (string, error) {
|
||||
tokenMatches := personalAccessTokenRegex.FindStringSubmatch(token)
|
||||
if len(tokenMatches) <= 1 {
|
||||
return "", errors.New("invalid token format")
|
||||
}
|
||||
tokenValue := tokenMatches[1]
|
||||
|
||||
return tokenValue, nil
|
||||
}
|
||||
var ParsePersonalAccessToken = libaccesstoken.ParsePersonalAccessToken
|
||||
|
||||
// GeneratePersonalAccessToken generates a new personal access token.
|
||||
// It returns the full token string, and the byte representation of the access token.
|
||||
|
||||
@ -6,93 +6,6 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParsePersonalAccessToken(t *testing.T) {
|
||||
type args struct {
|
||||
token string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
// Valid test cases
|
||||
{
|
||||
name: "no prefix",
|
||||
args: args{token: "abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "abcdef1234abcdef1234abcdef1234abcdef1234",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "sgp_ prefix",
|
||||
args: args{token: "sgp_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "abcdef1234abcdef1234abcdef1234abcdef1234",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "sgph_ prefix",
|
||||
args: args{token: "sgph_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "abcdef1234abcdef1234abcdef1234abcdef1234",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "sgph_ prefix and instance-identifier",
|
||||
args: args{token: "sgph_0123456789abcdef_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "abcdef1234abcdef1234abcdef1234abcdef1234",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "sgph_ prefix and local instance-identifier",
|
||||
args: args{token: "sgph_local_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "abcdef1234abcdef1234abcdef1234abcdef1234",
|
||||
wantErr: false,
|
||||
},
|
||||
// Error cases
|
||||
{
|
||||
name: "no prefix, invalid length",
|
||||
args: args{token: "abc123"},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid prefix, invalid length",
|
||||
args: args{token: "sgptest_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "prefix, invalid length",
|
||||
args: args{token: "sgp_abcdef1234abcdef1234abcdef1234abcdef12345"},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "too-short instance identifer",
|
||||
args: args{token: "sgph_01234_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "too-long instance identifer",
|
||||
args: args{token: "sgph_0123456789abcdef0_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ParsePersonalAccessToken(tt.args.token)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ParsePersonalAccessToken() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("ParsePersonalAccessToken() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeneratePersonalAccessToken(t *testing.T) {
|
||||
type args struct {
|
||||
licenseKey string
|
||||
|
||||
19
lib/accesstoken/BUILD.bazel
Normal file
19
lib/accesstoken/BUILD.bazel
Normal file
@ -0,0 +1,19 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("//dev:go_defs.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "accesstoken",
|
||||
srcs = ["personal_access_token.go"],
|
||||
importpath = "github.com/sourcegraph/sourcegraph/lib/accesstoken",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//lib/errors",
|
||||
"@com_github_grafana_regexp//:regexp",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "accesstoken_test",
|
||||
srcs = ["personal_access_token_test.go"],
|
||||
embed = [":accesstoken"],
|
||||
)
|
||||
29
lib/accesstoken/personal_access_token.go
Normal file
29
lib/accesstoken/personal_access_token.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Package accesstoken is exposed in lib/ for usage in src-cli
|
||||
package accesstoken
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/grafana/regexp" // avoid pulling in internal lazyregexp package
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/lib/errors"
|
||||
)
|
||||
|
||||
var makePersonalAccessTokenRegex = sync.OnceValue[*regexp.Regexp](func() *regexp.Regexp {
|
||||
return regexp.MustCompile("^(?:sgp_|sgph_)?(?:[a-fA-F0-9]{16}_|local_)?([a-fA-F0-9]{40})$")
|
||||
})
|
||||
|
||||
// ParsePersonalAccessToken parses a personal access token to remove prefixes and extract the <token> that is stored in the database
|
||||
// Personal access tokens can take several forms:
|
||||
// - <token>
|
||||
// - sgp_<token>
|
||||
// - sgp_<instance-identifier>_<token>
|
||||
func ParsePersonalAccessToken(token string) (string, error) {
|
||||
tokenMatches := makePersonalAccessTokenRegex().FindStringSubmatch(token)
|
||||
if len(tokenMatches) <= 1 {
|
||||
return "", errors.New("invalid token format")
|
||||
}
|
||||
tokenValue := tokenMatches[1]
|
||||
|
||||
return tokenValue, nil
|
||||
}
|
||||
92
lib/accesstoken/personal_access_token_test.go
Normal file
92
lib/accesstoken/personal_access_token_test.go
Normal file
@ -0,0 +1,92 @@
|
||||
package accesstoken
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParsePersonalAccessToken(t *testing.T) {
|
||||
type args struct {
|
||||
token string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
// Valid test cases
|
||||
{
|
||||
name: "no prefix",
|
||||
args: args{token: "abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "abcdef1234abcdef1234abcdef1234abcdef1234",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "sgp_ prefix",
|
||||
args: args{token: "sgp_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "abcdef1234abcdef1234abcdef1234abcdef1234",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "sgph_ prefix",
|
||||
args: args{token: "sgph_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "abcdef1234abcdef1234abcdef1234abcdef1234",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "sgph_ prefix and instance-identifier",
|
||||
args: args{token: "sgph_0123456789abcdef_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "abcdef1234abcdef1234abcdef1234abcdef1234",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "sgph_ prefix and local instance-identifier",
|
||||
args: args{token: "sgph_local_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "abcdef1234abcdef1234abcdef1234abcdef1234",
|
||||
wantErr: false,
|
||||
},
|
||||
// Error cases
|
||||
{
|
||||
name: "no prefix, invalid length",
|
||||
args: args{token: "abc123"},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid prefix, invalid length",
|
||||
args: args{token: "sgptest_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "prefix, invalid length",
|
||||
args: args{token: "sgp_abcdef1234abcdef1234abcdef1234abcdef12345"},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "too-short instance identifer",
|
||||
args: args{token: "sgph_01234_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "too-long instance identifer",
|
||||
args: args{token: "sgph_0123456789abcdef0_abcdef1234abcdef1234abcdef1234abcdef1234"},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ParsePersonalAccessToken(tt.args.token)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ParsePersonalAccessToken() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("ParsePersonalAccessToken() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -71,6 +71,7 @@ require (
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
github.com/hexops/gotextdiff v1.0.3 // indirect
|
||||
github.com/hexops/valast v1.4.3 // indirect
|
||||
|
||||
@ -125,8 +125,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
|
||||
Loading…
Reference in New Issue
Block a user