diff --git a/.gitignore b/.gitignore index 08dd7e0d4d56c7221f034ade6ff6a5eb9e9ba4c4..62c893550adb53d3a8fc29a1584ff831cb829062 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1 @@ -.idea/ -/spectre -/spectre.exe \ No newline at end of file +.idea/ \ No newline at end of file diff --git a/.woodpecker.yml b/.woodpecker.yml deleted file mode 100644 index 72e6341bb53bc67e052700c2a37851c4408fc8ef..0000000000000000000000000000000000000000 --- a/.woodpecker.yml +++ /dev/null @@ -1,58 +0,0 @@ -clone: - git: - image: woodpeckerci/plugin-git:next - -pipeline: - compliance: - image: golang:1.17 - commands: - - go test -race ./... - - go vet ./... - - go build - when: - event: pull_request - - build: - image: golang:1.17 - commands: - - GOOS="windows" go build ./cmd/spectre - - GOOS="linux" go build ./cmd/spectre - when: - event: [ push, tag ] - branch: main - - release-main: - image: jolheiser/drone-gitea-main:latest - secrets: - - source: gitea_token - target: plugin_token - base: https://git.jojodev.com - files: - - "spectre" - - "spectre.exe" - when: - event: push - branch: main - - release-tag: - image: plugins/gitea-release:1 - secrets: - - source: gitea_token - target: plugin_api_key - base_url: https://git.jojodev.com - files: - - "spectre" - - "spectre.exe" - when: - event: tag - tag: v* - - prune: - image: jolheiser/drone-gitea-prune - secrets: - - source: gitea_token - target: plugin_token - base: https://git.jojodev.com - when: - event: tag - tag: v* diff --git a/README.md b/README.md index 0e3437e84aed6508394c61ee93feca3c9987e8d8..d40829e34956d728e689da4851e09d63f171930d 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,8 @@ # Spectre - -[![Go Reference](https://pkg.go.dev/badge/go.jolheiser.com/go-spectre.svg)](https://pkg.go.dev/go.jolheiser.com/go-spectre) A Go implementation of [spectre](https://spectre.app). -Currently, it passes a sub-set of the [CLI tests](https://gitlab.com/spectre.app/cli/-/blob/main/spectre_tests.xml). -It also passes the JS [sanity check](https://gitlab.com/spectre.app/www/-/blob/306704b129a2c43544af202b8b6fb5c7e665ce66/assets/js/mpw-js/mpw.js#L205). +Currently it passes a sub-set of the [CLI tests](https://gitlab.com/spectre.app/cli/-/blob/main/spectre_tests.xml). This is because I've only implemented v3 of the algorithm and the main pieces. diff --git a/cmd/spectre/main.go b/cmd/spectre/main.go deleted file mode 100644 index 6f6a394c5eebf21e61f0bd7904b9ec9ad5085fc8..0000000000000000000000000000000000000000 --- a/cmd/spectre/main.go +++ /dev/null @@ -1,83 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - "strings" - - "go.jolheiser.com/spectre" -) - -func main() { - fs := flag.NewFlagSet("spectre", flag.ExitOnError) - usernameFlag := fs.String("username", "", "username") - secretFlag := fs.String("secret", "", "secret") - siteFlag := fs.String("site", "", "site") - counterFlag := fs.Int("counter", 1, "counter") - scoperFlag := fs.String("scoper", "com.lyndir.masterpassword", "scoper base") - scopeFlag := spectre.Authentication - fs.Func("scope", "scope", func(s string) (err error) { - scopeFlag, err = spectre.ParseScope(s) - return - }) - var templateFlag spectre.Template - fs.Func("template", "template", func(s string) (err error) { - templateFlag, err = spectre.ParseTemplate(s) - return - }) - - if err := fs.Parse(os.Args[1:]); err != nil { - panic(err) - } - if err := checkEnv(fs); err != nil { - panic(err) - } - - if templateFlag == "" { - templateFlag = scopeFlag.DefaultTemplate() - } - - if *usernameFlag == "" || *secretFlag == "" || *siteFlag == "" { - panic("username, secret, and site are required") - } - - s, err := spectre.New(*usernameFlag, *secretFlag, spectre.WithScoper(spectre.SimpleScoper{ - Key: *scoperFlag, - })) - if err != nil { - panic(err) - } - - pw := s.Site(*siteFlag, - spectre.WithScope(scopeFlag), - spectre.WithTemplate(templateFlag), - spectre.WithCounter(*counterFlag), - ) - - fmt.Println(pw) -} - -func checkEnv(fs *flag.FlagSet) error { - provided := map[string]struct{}{} - fs.Visit(func(f *flag.Flag) { - provided[f.Name] = struct{}{} - }) - var visitErr error - fs.VisitAll(func(f *flag.Flag) { - if visitErr != nil { - return - } - if _, ok := provided[f.Name]; ok { - return - } - env := os.Getenv(fmt.Sprintf("SPECTRE_%s", strings.ToUpper(f.Name))) - if env == "" { - return - } - if err := fs.Set(f.Name, env); err != nil { - visitErr = fmt.Errorf("could not set flag %q to %q", f.Name, env) - } - }) - return nil -} diff --git a/go.sum b/go.sum index 81601f9b9535b26839699a3de80cfabfe498c80e..49ae2ce2300a7a01d97e71944aff2f5154dfc415 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,13 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/scope.go b/scope.go index 8480e0569397ef22f59c3a47ab8b810a17422f33..7cd8baa598402c8d09a2ec2833c6234c51ab661f 100644 --- a/scope.go +++ b/scope.go @@ -1,13 +1,5 @@ package spectre -import ( - "errors" - "strings" -) - -// Interface guard -var _ Scoper = (*SimpleScoper)(nil) - // Scope is a key scope type Scope string @@ -16,34 +8,6 @@ Authentication Scope = "Authentication" Identification Scope = "Identification" Recovery Scope = "Recovery" ) - -// DefaultTemplate is the default Template for a Scope -func (s Scope) DefaultTemplate() Template { - switch s { - case Identification: - return Name - case Recovery: - return Phrase - case Authentication: - fallthrough - default: - return Long - } -} - -// ParseScope returns a Scope from s -func ParseScope(s string) (Scope, error) { - switch strings.ToLower(s) { - case "authentication", "a": - return Authentication, nil - case "identification", "i": - return Identification, nil - case "recovery", "r": - return Recovery, nil - default: - return "", errors.New("unknown Scope") - } -} // Scoper returns one of the three available scopes type Scoper interface { diff --git a/spectre.go b/spectre.go index 4f5ba3d5e7c8fb5e803c12093d7390c9ce25f5e1..db642df76c33b2e9c482c1e3a84355456999b324 100644 --- a/spectre.go +++ b/spectre.go @@ -11,14 +11,15 @@ // Spectre is a spectre client type Spectre struct { name string secret string - scoper Scoper + +// Spectre is a spectre client package spectre - "crypto/hmac" +import ( } // New returns a Spectre client -func New(name, secret string, opts ...Option) (s *Spectre, err error) { +func New(name, secret string, opts ...SpectreOption) (s *Spectre, err error) { s = &Spectre{ name: name, secret: secret, @@ -31,11 +32,11 @@ s.key, err = s.userKey() return } -// Option is a Spectre option +// SpectreOption is a Spectre option -type Option func(*Spectre) +type SpectreOption func(*Spectre) // WithScoper assigns a scoper to Spectre -func WithScoper(scoper Scoper) Option { +func WithScoper(scoper Scoper) SpectreOption { return func(s *Spectre) { s.scoper = scoper } @@ -86,16 +87,12 @@ // Site returns a site password based on Options func (s *Spectre) Site(siteName string, opts ...SiteOption) string { siteOpts := &options{ - template: "", + template: Long, counter: 1, scope: Authentication, } for _, opt := range opts { opt(siteOpts) - } - - if siteOpts.template == "" { - siteOpts.template = siteOpts.scope.DefaultTemplate() } siteKey := s.siteKey(siteName, siteOpts.counter, siteOpts.scope) @@ -119,10 +116,7 @@ scope Scope } ) -) package spectre - -) func WithTemplate(t Template) SiteOption { return func(opts *options) { @@ -131,15 +125,12 @@ } } ) - "golang.org/x/crypto/scrypt" -) "strings" return func(opts *options) { opts.counter = c } } -// WithScope specifies a Scope func WithScope(s Scope) SiteOption { return func(opts *options) { opts.scope = s diff --git a/spectre_test.go b/spectre_test.go index c132a2901c577daaeeb620bc36493a962ce36c9d..27deb2ddd0930082c53921851c35b51a36c9e1f9 100644 --- a/spectre_test.go +++ b/spectre_test.go @@ -1,12 +1,10 @@ -package spectre_test +package spectre import ( _ "embed" "encoding/xml" "strconv" "testing" - - "go.jolheiser.com/spectre" ) func TestSpectre(t *testing.T) { @@ -22,7 +20,7 @@ t.Run(tc.ID, func(t *testing.T) { user := def(dc.UserName, tc.UserName) secret := def(dc.UserSecret, tc.UserSecret) - s, err := spectre.New(user, secret) + s, err := New(user, secret) if err != nil { t.Logf("could not initialize spectre: %v", err) t.Fail() @@ -39,9 +37,9 @@ } scope := def(dc.KeyPurpose, tc.KeyPurpose) pass := s.Site(siteName, - spectre.WithTemplate(spectre.Template(template)), + WithTemplate(Template(template)), - spectre.WithCounter(counter), + WithCounter(counter), - spectre.WithScope(spectre.Scope(scope)), + WithScope(Scope(scope)), ) if pass != tc.Result { @@ -54,7 +52,7 @@ } // From the website sanity check func TestSanity(t *testing.T) { - s, err := spectre.New("Robert Lee Mitchell", "banana colored duckling") + s, err := New("Robert Lee Mitchell", "banana colored duckling") if err != nil { t.Logf("failed sanity check: %v", err) t.FailNow() diff --git a/template.go b/template.go index 5fb3ca2787aefe4d555616eef98e939582178659..f7eff748c401d4a449da7814af4228b1b5e901e2 100644 --- a/template.go +++ b/template.go @@ -1,10 +1,5 @@ package spectre -import ( - "errors" - "strings" -) - // Template is a template type type Template string @@ -18,30 +13,6 @@ Name Template = "Name" Phrase Template = "Phrase" Basic Template = "Basic" ) - -// ParseTemplate parses a Template from s -func ParseTemplate(s string) (Template, error) { - switch strings.ToLower(s) { - case "maximum", "max": - return Maximum, nil - case "long", "l": - return Long, nil - case "medium", "med": - return Medium, nil - case "short", "sh": - return Short, nil - case "pin": - return Pin, nil - case "name": - return Name, nil - case "phrase": - return Phrase, nil - case "basic": - return Basic, nil - default: - return "", errors.New("unknown Template") - } -} var templates = map[Template][]string{ Maximum: {