From 3a8666b99a37d2a3f8e423eca4c75f857ea93c0b Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Fri, 10 May 2024 19:32:14 +0800 Subject: [PATCH] chore: Expose ParsePersonalAccessToken publicly for src-cli (#62587) --- internal/accesstoken/BUILD.bazel | 3 +- internal/accesstoken/personal_access_token.go | 20 +--- .../accesstoken/personal_access_token_test.go | 87 ------------------ lib/accesstoken/BUILD.bazel | 19 ++++ lib/accesstoken/personal_access_token.go | 29 ++++++ lib/accesstoken/personal_access_token_test.go | 92 +++++++++++++++++++ lib/go.mod | 1 + lib/go.sum | 4 +- 8 files changed, 146 insertions(+), 109 deletions(-) create mode 100644 lib/accesstoken/BUILD.bazel create mode 100644 lib/accesstoken/personal_access_token.go create mode 100644 lib/accesstoken/personal_access_token_test.go diff --git a/internal/accesstoken/BUILD.bazel b/internal/accesstoken/BUILD.bazel index eb56d80d900..73e223add50 100644 --- a/internal/accesstoken/BUILD.bazel +++ b/internal/accesstoken/BUILD.bazel @@ -11,8 +11,7 @@ go_library( visibility = ["//:__subpackages__"], deps = [ "//internal/hashutil", - "//internal/lazyregexp", - "//lib/errors", + "//lib/accesstoken", ], ) diff --git a/internal/accesstoken/personal_access_token.go b/internal/accesstoken/personal_access_token.go index a9f71ec7a70..09fe4013fb7 100644 --- a/internal/accesstoken/personal_access_token.go +++ b/internal/accesstoken/personal_access_token.go @@ -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 that is stored in the database -// Personal access tokens can take several forms: -// - -// - sgp_ -// - sgp__ -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. diff --git a/internal/accesstoken/personal_access_token_test.go b/internal/accesstoken/personal_access_token_test.go index 839fff18c5f..8bfd896b7e8 100644 --- a/internal/accesstoken/personal_access_token_test.go +++ b/internal/accesstoken/personal_access_token_test.go @@ -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 diff --git a/lib/accesstoken/BUILD.bazel b/lib/accesstoken/BUILD.bazel new file mode 100644 index 00000000000..20207a053ff --- /dev/null +++ b/lib/accesstoken/BUILD.bazel @@ -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"], +) diff --git a/lib/accesstoken/personal_access_token.go b/lib/accesstoken/personal_access_token.go new file mode 100644 index 00000000000..92f4d13573e --- /dev/null +++ b/lib/accesstoken/personal_access_token.go @@ -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 that is stored in the database +// Personal access tokens can take several forms: +// - +// - sgp_ +// - sgp__ +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 +} diff --git a/lib/accesstoken/personal_access_token_test.go b/lib/accesstoken/personal_access_token_test.go new file mode 100644 index 00000000000..ff7b66ac4b2 --- /dev/null +++ b/lib/accesstoken/personal_access_token_test.go @@ -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) + } + }) + } +} diff --git a/lib/go.mod b/lib/go.mod index d0891162511..b1dd22966e1 100644 --- a/lib/go.mod +++ b/lib/go.mod @@ -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 diff --git a/lib/go.sum b/lib/go.sum index 7647fef8954..ac34cf3d1f3 100644 --- a/lib/go.sum +++ b/lib/go.sum @@ -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=