diff --git a/internal/backend/crypto.go b/internal/backend/crypto.go index 76b3d75ca4..5183c4eed4 100644 --- a/internal/backend/crypto.go +++ b/internal/backend/crypto.go @@ -76,7 +76,7 @@ func DetectCrypto(ctx context.Context, storage Storage) (Crypto, error) { for _, be := range CryptoRegistry.Prioritized() { debug.Log("Trying %s for %s", be, storage) - if err := be.Handles(storage); err != nil { + if err := be.Handles(ctx, storage); err != nil { debug.Log("failed to use crypto %s for %s", be, storage) continue } diff --git a/internal/backend/crypto/age/loader.go b/internal/backend/crypto/age/loader.go index c48b9a754b..1b2583b7aa 100644 --- a/internal/backend/crypto/age/loader.go +++ b/internal/backend/crypto/age/loader.go @@ -24,8 +24,7 @@ func (l loader) New(ctx context.Context) (backend.Crypto, error) { return New() } -func (l loader) Handles(s backend.Storage) error { - ctx := context.TODO() +func (l loader) Handles(ctx context.Context, s backend.Storage) error { if s.Exists(ctx, OldIDFile) || s.Exists(ctx, OldKeyring) { if err := migrate(ctx, s); err != nil { out.Errorf(ctx, "Failed to migrate age backend: %s", err) diff --git a/internal/backend/crypto/gpg/cli/loader.go b/internal/backend/crypto/gpg/cli/loader.go index 80862a537c..76ab4db9dc 100644 --- a/internal/backend/crypto/gpg/cli/loader.go +++ b/internal/backend/crypto/gpg/cli/loader.go @@ -30,8 +30,8 @@ func (l loader) New(ctx context.Context) (backend.Crypto, error) { }) } -func (l loader) Handles(s backend.Storage) error { - if s.Exists(context.TODO(), IDFile) { +func (l loader) Handles(ctx context.Context, s backend.Storage) error { + if s.Exists(ctx, IDFile) { return nil } return fmt.Errorf("not supported") diff --git a/internal/backend/crypto/plain/backend.go b/internal/backend/crypto/plain/backend.go index a8cb5433ed..a0de399516 100644 --- a/internal/backend/crypto/plain/backend.go +++ b/internal/backend/crypto/plain/backend.go @@ -9,6 +9,7 @@ import ( "time" "github.com/gopasspw/gopass/internal/backend/crypto/gpg" + "github.com/gopasspw/gopass/pkg/debug" "github.com/blang/semver/v4" ) @@ -108,7 +109,7 @@ func (m *Mocker) ImportPublicKey(context.Context, []byte) error { // Version returns dummy version info func (m *Mocker) Version(context.Context) semver.Version { - return semver.Version{} + return debug.ModuleVersion("github.com/gopasspw/gopass/internal/backend/crypto/plain") } // Binary always returns 'gpg' diff --git a/internal/backend/crypto/plain/loader.go b/internal/backend/crypto/plain/loader.go index 633aeb7d3a..cec42a25a7 100644 --- a/internal/backend/crypto/plain/loader.go +++ b/internal/backend/crypto/plain/loader.go @@ -24,8 +24,8 @@ func (l loader) New(ctx context.Context) (backend.Crypto, error) { return New(), nil } -func (l loader) Handles(s backend.Storage) error { - if s.Exists(context.TODO(), IDFile) { +func (l loader) Handles(ctx context.Context, s backend.Storage) error { + if s.Exists(ctx, IDFile) { return nil } return fmt.Errorf("not supported") diff --git a/internal/backend/registry.go b/internal/backend/registry.go index f7c6f35195..5a85eb405b 100644 --- a/internal/backend/registry.go +++ b/internal/backend/registry.go @@ -27,7 +27,7 @@ type CryptoLoader interface { fmt.Stringer Prioritized New(context.Context) (Crypto, error) - Handles(Storage) error + Handles(context.Context, Storage) error } // StorageLoader is the interface for creating a new storage backend. @@ -37,7 +37,7 @@ type StorageLoader interface { New(context.Context, string) (Storage, error) Init(context.Context, string) (Storage, error) Clone(context.Context, string, string) (Storage, error) - Handles(string) error + Handles(context.Context, string) error } // NewRegistry returns a new registry diff --git a/internal/backend/registry_test.go b/internal/backend/registry_test.go index aab2cf79ce..473495e551 100644 --- a/internal/backend/registry_test.go +++ b/internal/backend/registry_test.go @@ -22,7 +22,7 @@ func (l fakeCryptoLoader) String() string { return "fakecryptoloader" } -func (l fakeCryptoLoader) Handles(_ backend.Storage) error { +func (l fakeCryptoLoader) Handles(_ context.Context, _ backend.Storage) error { return nil } diff --git a/internal/backend/storage.go b/internal/backend/storage.go index 9a82747616..15350b6534 100644 --- a/internal/backend/storage.go +++ b/internal/backend/storage.go @@ -67,7 +67,7 @@ func DetectStorage(ctx context.Context, path string) (Storage, error) { for _, be := range StorageRegistry.Prioritized() { debug.Log("Trying %s for %s", be, path) - if err := be.Handles(path); err != nil { + if err := be.Handles(ctx, path); err != nil { debug.Log("failed to use %s for %s: %s", be, path, err) continue } diff --git a/internal/backend/storage/fs/fsck_test.go b/internal/backend/storage/fs/fsck_test.go index b4089e13ed..01837086b2 100644 --- a/internal/backend/storage/fs/fsck_test.go +++ b/internal/backend/storage/fs/fsck_test.go @@ -20,7 +20,7 @@ func TestFsck(t *testing.T) { l := &loader{} s, err := l.Init(ctx, path) assert.NoError(t, err) - assert.NoError(t, l.Handles(path)) + assert.NoError(t, l.Handles(ctx, path)) for _, fn := range []string{ filepath.Join(path, ".plain-ids"), diff --git a/internal/backend/storage/fs/loader.go b/internal/backend/storage/fs/loader.go index 79f805f7a8..acb7bef0aa 100644 --- a/internal/backend/storage/fs/loader.go +++ b/internal/backend/storage/fs/loader.go @@ -41,7 +41,7 @@ func (l loader) Clone(ctx context.Context, repo, path string) (backend.Storage, return l.New(ctx, path) } -func (l loader) Handles(path string) error { +func (l loader) Handles(ctx context.Context, path string) error { if fsutil.IsDir(path) { return nil } diff --git a/internal/backend/storage/fs/rcs_test.go b/internal/backend/storage/fs/rcs_test.go index 5a683a3c54..5bf4b21c53 100644 --- a/internal/backend/storage/fs/rcs_test.go +++ b/internal/backend/storage/fs/rcs_test.go @@ -23,7 +23,7 @@ func TestRCS(t *testing.T) { assert.NoError(t, g.Cmd(ctx, "foo", "bar")) assert.Error(t, g.Init(ctx, "foo", "bar")) assert.NoError(t, g.InitConfig(ctx, "foo", "bar")) - assert.Equal(t, g.Version(ctx), semver.Version{Minor: 1}) + assert.Equal(t, true, g.Version(ctx).EQ(semver.Version{}), "Version eq 0.0.0") assert.Equal(t, "fs", g.Name()) assert.NoError(t, g.AddRemote(ctx, "foo", "bar")) revs, err := g.Revisions(ctx, "foo") diff --git a/internal/backend/storage/fs/store.go b/internal/backend/storage/fs/store.go index 6c67e0a47d..42e2cc2adb 100644 --- a/internal/backend/storage/fs/store.go +++ b/internal/backend/storage/fs/store.go @@ -176,12 +176,12 @@ func (s *Store) Name() string { // Version returns the version of this backend func (s *Store) Version(context.Context) semver.Version { - return semver.Version{Minor: 1} + return debug.ModuleVersion("github.com/gopasspw/gopass/internal/backend/fs") } // String implements fmt.Stringer func (s *Store) String() string { - return fmt.Sprintf("fs(v0.1.0,path:%s)", s.path) + return fmt.Sprintf("fs(%s,path:%s)", s.Version(context.TODO()).String(), s.path) } // Path returns the path to this storage diff --git a/internal/backend/storage/gitfs/git.go b/internal/backend/storage/gitfs/git.go index 7d98c2dee3..cb60bfc01a 100644 --- a/internal/backend/storage/gitfs/git.go +++ b/internal/backend/storage/gitfs/git.go @@ -58,7 +58,7 @@ func New(path string) (*Git, error) { // Clone clones an existing git repo and returns a new cli based git backend // configured for this clone repo -func Clone(ctx context.Context, repo, path string) (*Git, error) { +func Clone(ctx context.Context, repo, path, userName, userEmail string) (*Git, error) { g := &Git{ fs: fs.New(path), } @@ -67,7 +67,7 @@ func Clone(ctx context.Context, repo, path string) (*Git, error) { } // initialize the local git config - if err := g.InitConfig(ctx, "", ""); err != nil { + if err := g.InitConfig(ctx, userName, userEmail); err != nil { return g, fmt.Errorf("failed to configure git: %s", err) } out.Printf(ctx, "git configured at %s", g.fs.Path()) diff --git a/internal/backend/storage/gitfs/git_test.go b/internal/backend/storage/gitfs/git_test.go index 4cd1447fbd..2372f879b2 100644 --- a/internal/backend/storage/gitfs/git_test.go +++ b/internal/backend/storage/gitfs/git_test.go @@ -66,7 +66,7 @@ func TestGit(t *testing.T) { }) t.Run("clone existing repo", func(t *testing.T) { - git, err := Clone(ctx, gitdir, gitdir2) + git, err := Clone(ctx, gitdir, gitdir2, "", "") require.NoError(t, err) require.NotNil(t, git) assert.Equal(t, "git", git.Name()) diff --git a/internal/backend/storage/gitfs/loader.go b/internal/backend/storage/gitfs/loader.go index e6e7730bc5..f03b68eb36 100644 --- a/internal/backend/storage/gitfs/loader.go +++ b/internal/backend/storage/gitfs/loader.go @@ -31,7 +31,7 @@ func (l loader) Open(ctx context.Context, path string) (backend.Storage, error) // Clone implements backend.RCSLoader func (l loader) Clone(ctx context.Context, repo, path string) (backend.Storage, error) { - return Clone(ctx, repo, path) + return Clone(ctx, repo, path, termio.DetectName(ctx, nil), termio.DetectEmail(ctx, nil)) } // Init implements backend.RCSLoader @@ -39,7 +39,7 @@ func (l loader) Init(ctx context.Context, path string) (backend.Storage, error) return Init(ctx, path, termio.DetectName(ctx, nil), termio.DetectEmail(ctx, nil)) } -func (l loader) Handles(path string) error { +func (l loader) Handles(ctx context.Context, path string) error { if !fsutil.IsDir(filepath.Join(path, ".git")) { return fmt.Errorf("no .git") } diff --git a/internal/out/print.go b/internal/out/print.go index 1b1ee098ac..f2d3f6d4c5 100644 --- a/internal/out/print.go +++ b/internal/out/print.go @@ -42,7 +42,11 @@ func newline(ctx context.Context) string { // Print prints the given string func Print(ctx context.Context, arg any) { - Printf(ctx, "%s", arg) + if ctxutil.IsHidden(ctx) { + return + } + debug.LogN(1, "%s", arg) + fmt.Fprintf(Stdout, Prefix(ctx)+"%s"+newline(ctx), arg) } // Printf formats and prints the given string @@ -56,7 +60,11 @@ func Printf(ctx context.Context, format string, args ...any) { // Notice prints the string with an exclamation mark func Notice(ctx context.Context, arg any) { - Noticef(ctx, "%s", arg) + if ctxutil.IsHidden(ctx) { + return + } + debug.LogN(1, "NOTICE: %s", arg) + fmt.Fprintf(Stdout, Prefix(ctx)+"⚠ %s"+newline(ctx), arg) } // Noticef prints the string with an exclamation mark in front @@ -70,7 +78,11 @@ func Noticef(ctx context.Context, format string, args ...any) { // Error prints the string with a red cross in front func Error(ctx context.Context, arg any) { - Errorf(ctx, "%s", arg) + if ctxutil.IsHidden(ctx) { + return + } + debug.LogN(1, "ERROR: %s", arg) + fmt.Fprint(Stderr, color.RedString(Prefix(ctx)+"❌ %s"+newline(ctx), arg)) } // Errorf prints the string in red to stderr @@ -84,7 +96,11 @@ func Errorf(ctx context.Context, format string, args ...any) { // OK prints the string with a green checkmark in front func OK(ctx context.Context, arg any) { - OKf(ctx, "%s", arg) + if ctxutil.IsHidden(ctx) { + return + } + debug.LogN(1, "OK: %s", arg) + fmt.Fprintf(Stdout, Prefix(ctx)+"✅ %s"+newline(ctx), arg) } // OKf prints the string in with an OK checkmark in front @@ -98,7 +114,11 @@ func OKf(ctx context.Context, format string, args ...any) { // Warning prints the string with a warning sign in front func Warning(ctx context.Context, arg any) { - Warningf(ctx, "%s", arg) + if ctxutil.IsHidden(ctx) { + return + } + debug.LogN(1, "WARNING: %s", arg) + fmt.Fprint(Stderr, color.YellowString(Prefix(ctx)+"⚠ %s"+newline(ctx), arg)) } // Warningf prints the string in yellow to stderr and prepends a warning sign diff --git a/internal/store/leaf/rcs_test.go b/internal/store/leaf/rcs_test.go index e5b9578ea3..1d6c5522c4 100644 --- a/internal/store/leaf/rcs_test.go +++ b/internal/store/leaf/rcs_test.go @@ -28,7 +28,7 @@ func TestGit(t *testing.T) { require.NotNil(t, s.Storage()) require.Equal(t, "fs", s.Storage().Name()) assert.NoError(t, s.Storage().InitConfig(ctx, "foo", "bar@baz.com")) - assert.Equal(t, semver.Version{Minor: 1}, s.Storage().Version(ctx)) + assert.Equal(t, semver.Version{}, s.Storage().Version(ctx)) assert.NoError(t, s.Storage().AddRemote(ctx, "foo", "bar")) // RCS ops not supported by the fs backend assert.Error(t, s.Storage().Pull(ctx, "origin", "master")) diff --git a/internal/store/leaf/store.go b/internal/store/leaf/store.go index 50a42c1464..edbdacccee 100644 --- a/internal/store/leaf/store.go +++ b/internal/store/leaf/store.go @@ -29,17 +29,17 @@ func Init(ctx context.Context, alias, path string) (*Store, error) { st, err := backend.InitStorage(ctx, backend.GetStorageBackend(ctx), path) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to initialize storage for %s at %s: %w", alias, path, err) } s.storage = st - debug.Log("Storage initialized") + debug.Log("Storage for %s => %s initialized as %s", alias, path, st.Name()) crypto, err := backend.NewCrypto(ctx, backend.GetCryptoBackend(ctx)) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to initialize crypto for %s at %s: %w", alias, path, err) } s.crypto = crypto - debug.Log("Crypto initialized") + debug.Log("Crypto for %s => %s initialized as %s", alias, path, crypto.Name()) return s, nil } @@ -57,15 +57,14 @@ func New(ctx context.Context, alias, path string) (*Store, error) { if err := s.initStorageBackend(ctx); err != nil { return nil, fmt.Errorf("failed to init storage backend: %w", err) } - debug.Log("Storage initialized") + debug.Log("Storage for %s => %s initialized as %s", alias, path, s.storage) // init crypto backend if err := s.initCryptoBackend(ctx); err != nil { return nil, fmt.Errorf("failed to init crypto backend: %w", err) } - debug.Log("Crypto initialized") + debug.Log("Crypto for %s => %s initialized as %s", alias, path, s.crypto) - debug.Log("Instantiated %s at %s - storage: %+#v - crypto: %+#v", alias, path, s.storage, s.crypto) return s, nil } @@ -106,6 +105,8 @@ func (s *Store) idFiles(ctx context.Context) []string { return nil } + // we need to transform the list of files into a list of id files so we can't use + // set.SortedFiltered as it doesn't support transformations idfs := make([]string, 0, len(files)) for _, f := range files { if strings.HasPrefix(filepath.Base(f), ".") { @@ -121,7 +122,7 @@ func (s *Store) idFiles(ctx context.Context) []string { return set.Sorted(idfs) } -// Equals returns true if this.storage has the same on-disk path as the other +// Equals returns true if this storage has the same on-disk path as the other func (s *Store) Equals(other *Store) bool { if other == nil { return false diff --git a/internal/store/mockstore/inmem/store.go b/internal/store/mockstore/inmem/store.go index 382764a1fe..8a5ed6041e 100644 --- a/internal/store/mockstore/inmem/store.go +++ b/internal/store/mockstore/inmem/store.go @@ -14,7 +14,7 @@ import ( "golang.org/x/exp/maps" ) -// InMem is a in-memory store +// InMem is a thread-safe in-memory store type InMem struct { sync.Mutex data map[string][]byte @@ -23,7 +23,7 @@ type InMem struct { // New creates a new mock func New() *InMem { return &InMem{ - data: make(map[string][]byte, 10), + data: make(map[string][]byte, 128), } } @@ -32,10 +32,17 @@ func (m *InMem) Get(ctx context.Context, name string) ([]byte, error) { m.Lock() defer m.Unlock() + if m.data == nil { + return nil, fmt.Errorf("entry not found") + } + sec, found := m.data[name] if !found { + // not found return nil, fmt.Errorf("entry not found") } + + // found return sec, nil } diff --git a/internal/store/root/convert.go b/internal/store/root/convert.go index 3bc29dda47..860a79d6c5 100644 --- a/internal/store/root/convert.go +++ b/internal/store/root/convert.go @@ -14,6 +14,7 @@ func (r *Store) Convert(ctx context.Context, name string, cryptoBe backend.Crypt if err != nil { return err } + debug.Log("converting %s to crypto: %s, rcs: %s, storage: %s", name, cryptoBe, storageBe) if err := sub.Convert(ctx, cryptoBe, storageBe, move); err != nil { return err diff --git a/internal/store/root/fsck.go b/internal/store/root/fsck.go index 27a1c5ef38..0e534eb7c2 100644 --- a/internal/store/root/fsck.go +++ b/internal/store/root/fsck.go @@ -21,12 +21,16 @@ func (s *Store) Fsck(ctx context.Context, path string) error { continue } path = strings.TrimPrefix(path, alias+"/") + + // check sub store debug.Log("Checking %s", alias) if err := sub.Fsck(ctx, path); err != nil { out.Errorf(ctx, "fsck failed on sub store %s: %s", alias, err) result = multierror.Append(result, err) } } + + // check root store if err := s.store.Fsck(ctx, path); err != nil { out.Errorf(ctx, "fsck failed on root store: %s", err) result = multierror.Append(result, err) diff --git a/internal/store/root/init.go b/internal/store/root/init.go index bba7daf3b5..9c673c1b7b 100644 --- a/internal/store/root/init.go +++ b/internal/store/root/init.go @@ -19,6 +19,7 @@ func (r *Store) IsInitialized(ctx context.Context) (bool, error) { return false, fmt.Errorf("failed to initialize stores: %w", err) } } + debug.Log("root store is initialized") return r.store.IsInitialized(ctx), nil } @@ -32,6 +33,7 @@ func (r *Store) Init(ctx context.Context, alias, path string, ids ...string) err if !backend.HasStorageBackend(ctx) { ctx = backend.WithStorageBackend(ctx, backend.GitFS) } + sub, err := leaf.New(ctx, alias, path) if err != nil { return fmt.Errorf("failed to instantiate new sub store: %w", err) diff --git a/internal/store/root/mount.go b/internal/store/root/mount.go index 881102696f..4a512f7e89 100644 --- a/internal/store/root/mount.go +++ b/internal/store/root/mount.go @@ -11,8 +11,6 @@ import ( "github.com/gopasspw/gopass/internal/store/leaf" "github.com/gopasspw/gopass/pkg/debug" "github.com/gopasspw/gopass/pkg/fsutil" - - "github.com/fatih/color" ) // AddMount adds a new mount @@ -71,13 +69,15 @@ func (r *Store) initSub(ctx context.Context, alias, path string, keys []string) debug.Log("[%s] No keys available", alias) return s, NotInitializedError{alias, path} } + debug.Log("[%s] Trying to initialize at %s for %+v", alias, path, keys) if err := s.Init(ctx, path, keys...); err != nil { return s, fmt.Errorf("failed to initialize store %q at %q: %w", alias, path, err) } + out.Printf(ctx, "Password store %s initialized for:", path) for _, r := range s.Recipients(ctx) { - color.Yellow(r) + out.Noticef(ctx, " %s", r) } return s, nil @@ -127,7 +127,8 @@ func (r *Store) MountPoint(name string) string { return "" } -// Lock drops all cached credentials +// Lock drops all cached credentials, if any. Mostly only useful +// for the gopass REPL. func (r *Store) Lock() error { for _, sub := range r.mounts { if err := sub.Lock(); err != nil { @@ -157,6 +158,7 @@ func (r *Store) GetSubStore(name string) (*leaf.Store, error) { if sub, found := r.mounts[name]; found { return sub, nil } + debug.Log("mounts available: %+v", r.mounts) return nil, fmt.Errorf("no such mount point %q", name) } diff --git a/internal/store/root/move.go b/internal/store/root/move.go index 4643455f12..d868a76f4b 100644 --- a/internal/store/root/move.go +++ b/internal/store/root/move.go @@ -42,6 +42,7 @@ func (r *Store) move(ctx context.Context, from, to string, delete bool) error { if err := r.moveFromTo(ctx, subFrom, from, to, fromPrefix, srcIsDir, dstIsDir, delete); err != nil { return err } + if err := subFrom.Storage().Commit(ctx, fmt.Sprintf("Move from %s to %s", from, to)); delete && err != nil { switch { case errors.Is(err, store.ErrGitNotInit): @@ -50,6 +51,7 @@ func (r *Store) move(ctx context.Context, from, to string, delete bool) error { return fmt.Errorf("failed to commit changes to git (from): %w", err) } } + if !subFrom.Equals(subTo) { if err := subTo.Storage().Commit(ctx, fmt.Sprintf("Move from %s to %s", from, to)); err != nil { switch errors.Unwrap(err) { @@ -76,6 +78,7 @@ func (r *Store) move(ctx context.Context, from, to string, delete bool) error { } return fmt.Errorf("failed to push change to git remote: %w", err) } + if !subFrom.Equals(subTo) { if err := subTo.Storage().Push(ctx, "", ""); err != nil { if errors.Is(err, store.ErrGitNotInit) { @@ -93,6 +96,7 @@ func (r *Store) move(ctx context.Context, from, to string, delete bool) error { return fmt.Errorf("failed to push change to git remote: %w", err) } } + return nil } diff --git a/internal/store/root/recipients.go b/internal/store/root/recipients.go index d32bc6a661..2c43531ffd 100644 --- a/internal/store/root/recipients.go +++ b/internal/store/root/recipients.go @@ -45,6 +45,7 @@ func (r *Store) addRecipient(ctx context.Context, prefix string, root *tree.Root } } } + // workaround to keep key names from breaking the folder structure. // A proper fix should change tree.AddFile to take a path and file name // (which could then contain slashes). diff --git a/internal/tree/root.go b/internal/tree/root.go index d32a90d67f..b6c2172a17 100644 --- a/internal/tree/root.go +++ b/internal/tree/root.go @@ -1,7 +1,6 @@ package tree import ( - "bytes" "fmt" "path/filepath" "strings" @@ -57,6 +56,9 @@ func (r *Root) AddTemplate(path string) error { func (r *Root) insert(path string, template bool, mountPath string) error { t := r.Subtree + + // split the path into its components, iterate over them and create + // the tree structure. Everything but the last element is a folder. p := strings.Split(path, "/") for i, e := range p { n := &Node{ @@ -64,6 +66,7 @@ func (r *Root) insert(path string, template bool, mountPath string) error { Type: "dir", Subtree: NewTree(), } + // this is the final element (a leaf) if i == len(p)-1 { n.Type = "file" n.Subtree = nil @@ -79,6 +82,8 @@ func (r *Root) insert(path string, template bool, mountPath string) error { node.Subtree = NewTree() node.Type = "dir" } + + // re-root t to the new subtree t = node.Subtree } return nil @@ -87,20 +92,20 @@ func (r *Root) insert(path string, template bool, mountPath string) error { // Format returns a pretty printed string of all nodes in and below // this node, e.g. ├── baz func (r *Root) Format(maxDepth int) string { - out := &bytes.Buffer{} + var sb strings.Builder // any mount will be colored and include the on-disk path - _, _ = out.WriteString(colDir(r.Name)) + _, _ = sb.WriteString(colDir(r.Name)) // finish this folders output - _, _ = out.WriteString("\n") + _, _ = sb.WriteString("\n") // let our children format themselves for i, node := range r.Subtree.Nodes { last := i == len(r.Subtree.Nodes)-1 - _, _ = out.WriteString(node.format("", last, maxDepth, 1)) + _, _ = sb.WriteString(node.format("", last, maxDepth, 1)) } - return out.String() + return sb.String() } // List returns a flat list of all files in this tree diff --git a/internal/tree/tree.go b/internal/tree/tree.go index 8b2e98c391..5526e2c48c 100644 --- a/internal/tree/tree.go +++ b/internal/tree/tree.go @@ -51,6 +51,7 @@ func (t *Tree) Insert(node *Node) (*Node, error) { return t.Nodes[pos], fmt.Errorf("node %q already preset", node.Name) } + // insert at the right position, see // https://code.google.com/p/go-wiki/wiki/SliceTricks t.Nodes = append(t.Nodes, &Node{}) copy(t.Nodes[pos+1:], t.Nodes[pos:]) diff --git a/internal/updater/download.go b/internal/updater/download.go index 6fabda9b94..cf7229dd75 100644 --- a/internal/updater/download.go +++ b/internal/updater/download.go @@ -15,9 +15,15 @@ import ( "golang.org/x/net/context/ctxhttp" ) +// DownloadTimeout is the overall timeout for the download, including all retries +var DownloadTimeout = time.Minute * 5 + func tryDownload(ctx context.Context, url string) ([]byte, error) { + ctx, cancel := context.WithTimeout(ctx, DownloadTimeout) + defer cancel() + bo := backoff.NewExponentialBackOff() - bo.MaxElapsedTime = 5 * time.Minute + bo.MaxElapsedTime = DownloadTimeout var buf []byte diff --git a/internal/updater/extract.go b/internal/updater/extract.go index 3942992ad6..c9db7876b1 100644 --- a/internal/updater/extract.go +++ b/internal/updater/extract.go @@ -29,6 +29,7 @@ func extractFile(buf []byte, filename, dest string) error { } } + // open the destination file for writing dfh, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE|os.O_EXCL, mode) if err != nil { return fmt.Errorf("failed to open file %q: %w", dest, err) @@ -50,7 +51,7 @@ func extractFile(buf []byte, filename, dest string) error { case ".zip": return extractZip(buf, dfh, dest) default: - return fmt.Errorf("unsupported") + return fmt.Errorf("unsupported file extension: %q", filepath.Ext(filename)) } } diff --git a/pkg/clipboard/clipboard.go b/pkg/clipboard/clipboard.go index ece7838fa3..929961e3f6 100644 --- a/pkg/clipboard/clipboard.go +++ b/pkg/clipboard/clipboard.go @@ -15,7 +15,7 @@ import ( var ( // Helpers can be overridden at compile time, e.g. go build \ // -ldflags=='-X github.com/gopasspw/gopass/pkg/clipboard.Helpers=termux-api' - Helpers = "xsel of xclip" + Helpers = "xsel or xclip" // ErrNotSupported is returned when the clipboard is not accessible ErrNotSupported = fmt.Errorf("WARNING: No clipboard available. Install " + Helpers + " or use -f to print to console") ) diff --git a/pkg/debug/debug.go b/pkg/debug/debug.go index 283e7122de..d139777db4 100644 --- a/pkg/debug/debug.go +++ b/pkg/debug/debug.go @@ -55,7 +55,8 @@ func initDebugLogger() { f, err := os.OpenFile(debugfile, os.O_WRONLY|os.O_APPEND, 0600) if err == nil { - _, err := f.Seek(2, 0) + // seek to the end of the file (offset, whence [2 = end]) + _, err := f.Seek(0, 2) if err != nil { fmt.Fprintf(Stderr, "unable to seek to end of %v: %v\n", debugfile, err) os.Exit(3) diff --git a/pkg/debug/version.go b/pkg/debug/version.go index c1a02ba7e6..bb87ed48b2 100644 --- a/pkg/debug/version.go +++ b/pkg/debug/version.go @@ -26,5 +26,6 @@ func ModuleVersion(m string) semver.Version { } return sv } + Log("no module %s found", m) return semver.Version{} } diff --git a/pkg/fsutil/fsutil.go b/pkg/fsutil/fsutil.go index ae8ac308ac..ac0a62f3bb 100644 --- a/pkg/fsutil/fsutil.go +++ b/pkg/fsutil/fsutil.go @@ -99,22 +99,47 @@ func Shred(path string, runs int) error { if err != nil { return fmt.Errorf("failed to open file %q: %w", path, err) } - buf := make([]byte, 1024) + // ignore the error. this is only taking effect if we error out. + defer fh.Close() + + fi, err := fh.Stat() + if err != nil { + return fmt.Errorf("failed to stat file %q: %w", path, err) + } + flen := fi.Size() + + // overwrite using pseudo-random data n-1 times and + // use zeros in the last iteration + bufFn := func() []byte { + buf := make([]byte, 1024) + _, _ = rand.Read(buf) + return buf + } for i := 0; i < runs; i++ { - // overwrite using pseudo-random data n-1 times and - // use zeros in the last iteration - if i < runs-1 { - _, _ = rand.Read(buf) - } else { - buf = make([]byte, 1024) + if i >= runs-1 { + bufFn = func() []byte { + return make([]byte, 1024) + } } if _, err := fh.Seek(0, 0); err != nil { return fmt.Errorf("failed to seek to 0,0: %w", err) } - if _, err := fh.Write(buf); err != nil { - if err != io.EOF { - return fmt.Errorf("failed to write to file: %w", err) + var written int64 + for { + // end of file + if written >= flen { + break + } + buf := bufFn() + n, err := fh.Write(buf[0:min(flen-written, int64(len(buf)))]) + if err != nil { + if err != io.EOF { + return fmt.Errorf("failed to write to file: %w", err) + } + // end of file, should not happen + break } + written += int64(n) } // if we fail to sync the written blocks to disk it'd be pointless // do any further loops @@ -147,3 +172,10 @@ func FileContains(path, needle string) bool { } return false } + +func min(a, b int64) int64 { + if a < b { + return a + } + return b +} diff --git a/pkg/gopass/secrets/kv.go b/pkg/gopass/secrets/kv.go index 1a09af8c26..ed5cf82bfb 100644 --- a/pkg/gopass/secrets/kv.go +++ b/pkg/gopass/secrets/kv.go @@ -10,6 +10,7 @@ import ( "github.com/gopasspw/gopass/pkg/debug" "github.com/gopasspw/gopass/pkg/gopass" + "golang.org/x/exp/maps" ) var _ gopass.Secret = &KV{} @@ -107,10 +108,7 @@ func (k *KV) Bytes() []byte { // Keys returns all keys func (k *KV) Keys() []string { - keys := make([]string, 0, len(k.data)+1) - for key := range k.data { - keys = append(keys, key) - } + keys := maps.Keys(k.data) sort.Strings(keys) return keys } diff --git a/pkg/gopass/secrets/secparse/.gitignore b/pkg/gopass/secrets/secparse/.gitignore new file mode 100644 index 0000000000..fb94ebfb92 --- /dev/null +++ b/pkg/gopass/secrets/secparse/.gitignore @@ -0,0 +1 @@ +testdata/ \ No newline at end of file diff --git a/pkg/gopass/secrets/secparse/parse_test.go b/pkg/gopass/secrets/secparse/parse_test.go index a10f431fed..dac923f4c1 100644 --- a/pkg/gopass/secrets/secparse/parse_test.go +++ b/pkg/gopass/secrets/secparse/parse_test.go @@ -37,3 +37,25 @@ func TestParsedIsSerialized(t *testing.T) { assert.Equal(t, tc, string(sec.Bytes())) } } + +func FuzzParse(f *testing.F) { + for _, tc := range []string{ + "foo\n", // Plain + "foo\nbar\n", // Plain + "foo\nbar: baz\n", // KV + "foo\nbar\n---\nzab: 1\n", // YAML + secrets.Ident + "\nFoo: Bar\n\nBarfoo\n", // MIME + secrets.Ident + "\nFoo: Bar\n\nBarfoo", // MIME + } { + f.Add(tc) + } + f.Fuzz(func(t *testing.T, in string) { + sec, err := Parse([]byte(in)) + if err != nil { + t.Fatalf("Parse failed to decode a valid secret %q: %v", in, err) + } + if sec == nil { + t.Errorf("secret should not be nil") + } + }) +} diff --git a/pkg/gopass/secrets/yaml.go b/pkg/gopass/secrets/yaml.go index 72df470144..4a75845740 100644 --- a/pkg/gopass/secrets/yaml.go +++ b/pkg/gopass/secrets/yaml.go @@ -12,6 +12,7 @@ import ( "github.com/gopasspw/gopass/internal/out" "github.com/gopasspw/gopass/pkg/debug" "github.com/gopasspw/gopass/pkg/gopass" + "golang.org/x/exp/maps" yaml "gopkg.in/yaml.v3" ) @@ -38,10 +39,7 @@ type YAML struct { // Keys returns all keys func (y *YAML) Keys() []string { - keys := make([]string, 0, len(y.data)+1) - for key := range y.data { - keys = append(keys, key) - } + keys := maps.Keys(y.data) sort.Strings(keys) return keys } diff --git a/pkg/pwgen/pwrules/gen.go b/pkg/pwgen/pwrules/gen.go index 47cdd3600c..db71c39162 100644 --- a/pkg/pwgen/pwrules/gen.go +++ b/pkg/pwgen/pwrules/gen.go @@ -16,6 +16,9 @@ import ( "strings" "text/template" "time" + + "github.com/gopasspw/gopass/pkg/debug" + "github.com/gopasspw/gopass/pkg/pwgen/pwrules" ) const ( @@ -33,7 +36,7 @@ func main() { if err != nil { panic(err) } - rules, err := fetchRules() + jsonRules, err := fetchRules() if err != nil { panic(err) } @@ -44,12 +47,14 @@ func main() { } defer f.Close() + rules := parseRules(jsonRules) + pkgTpl.Execute(f, struct { Timestamp time.Time URLs []string Aliases map[string][]string Changes map[string]string - Rules map[string]jsonRule + Rules map[string]pwrules.Rule }{ Timestamp: time.Now().UTC(), URLs: []string{ @@ -175,8 +180,20 @@ func (c *cleaningReader) Read(p []byte) (n int, err error) { return c.rdr.Read(p) } +func parseRules(jr map[string]jsonRule) map[string]pwrules.Rule { + rules := make(map[string]pwrules.Rule, len(jr)) + for domain, jr := range jr { + r := pwrules.ParseRule(jr.Rules) + r.Exact = jr.Exact + rules[domain] = r + } + return rules +} + // cf. https://blog.carlmjohnson.net/post/2016-11-27-how-to-use-go-generate/ -var pkgTpl = template.Must(template.New("").Parse(`// Code generated by go generate gen.go. DO NOT EDIT. +var pkgTpl = template.Must(template.New("").Funcs(template.FuncMap{ + "trimPrefix": func(prefix, s string) string { return strings.TrimPrefix(s, prefix) }, +}).Parse(`// Code generated by go generate gen.go. DO NOT EDIT. // This package was generated by go generate gen.go at // {{ .Timestamp }} // using data from @@ -201,15 +218,10 @@ var genChange = map[string]string{ {{- end }} } -var genRules = map[string]string{ +var genRules = map[string]Rule{ {{- range $key, $value := .Rules }} - "{{ $key }}": {{ printf "%q" $value.Rules }}, + "{{ $key }}": {{ printf "%#v" $value | trimPrefix "pwrules." }}, {{- end }} } -var genRulesExact = map[string]bool{ -{{- range $key, $value := .Rules }} - "{{ $key }}": {{ printf "%t" $value.Exact }}, -{{- end }} -} `)) diff --git a/pkg/pwgen/pwrules/pwrules.go b/pkg/pwgen/pwrules/pwrules.go index b34a9e6a1e..c0f8f464c7 100644 --- a/pkg/pwgen/pwrules/pwrules.go +++ b/pkg/pwgen/pwrules/pwrules.go @@ -1,7 +1,6 @@ package pwrules import ( - "math" "regexp" "sort" "strconv" @@ -13,40 +12,23 @@ import ( //go:generate go run gen.go var ( - rules = map[string]Rule{} reChars = regexp.MustCompile(`(allowed|required):\s*\[(.*)\](?:;|,)`) ) -func init() { - for k, v := range genRules { - // do not override customizations - if _, found := rules[k]; found { - continue - } - r := ParseRule(v) - r.Exact = genRulesExact[k] - if r.Maxlen < 1 { - r.Maxlen = math.MaxInt32 - } - rules[k] = r - //debug.Log("added rule for %q from %q: %+v", k, v, r) - } -} - // AllRules returns all rules func AllRules() map[string]Rule { - return rules + return genRules } // LookupRule looks up a rule either directly or through one of it's know // aliases. func LookupRule(domain string) (Rule, bool) { - r, found := rules[domain] + r, found := genRules[domain] if found { return r, true } for _, alias := range LookupAliases(domain) { - if r, found := rules[alias]; found { + if r, found := genRules[alias]; found { return r, true } } diff --git a/pkg/pwgen/pwrules/pwrules_gen.go b/pkg/pwgen/pwrules/pwrules_gen.go index e1a6a31e5d..b31526332c 100644 --- a/pkg/pwgen/pwrules/pwrules_gen.go +++ b/pkg/pwgen/pwrules/pwrules_gen.go @@ -1,6 +1,6 @@ // Code generated by go generate gen.go. DO NOT EDIT. // This package was generated by go generate gen.go at -// 2021-12-03 09:01:08.035156851 +0000 UTC +// 2021-12-22 12:32:29.315327 +0000 UTC // using data from // // https://raw.githubusercontent.com/apple/password-manager-resources/main/quirks/websites-with-shared-credential-backends.json @@ -7108,494 +7108,252 @@ var genChange = map[string]string{ "zoom.us": "https://zoom.us/profile#pwd-form", } -var genRules = map[string]string{ - "163.com": "minlength: 6; maxlength: 16;", - "1800flowers.com": "minlength: 6; required: lower, upper; required: digit;", - "access.service.gov.uk": "minlength: 10; required: lower; required: upper; required: digit; required: special;", - "admiral.com": "minlength: 8; required: digit; required: [- !\"#$&'()*+,.:;<=>?@[^_`{|}~]]; allowed: lower, upper;", - "ae.com": "minlength: 8; maxlength: 25; required: lower; required: upper; required: digit;", - "aetna.com": "minlength: 8; maxlength: 20; max-consecutive: 2; required: upper; required: digit; allowed: lower, [-_&#@];", - "airasia.com": "minlength: 8; maxlength: 15; required: lower; required: upper; required: digit;", - "ajisushionline.com": "minlength: 8; required: lower; required: upper; required: digit; allowed: [ !#$%&*?@];", - "aliexpress.com": "minlength: 6; maxlength: 20; allowed: lower, upper, digit;", - "alliantcreditunion.com": "minlength: 8; maxlength: 20; max-consecutive: 3; required: lower, upper; required: digit; allowed: [!#$*];", - "allianz.com.br": "minlength: 4; maxlength: 4;", - "americanexpress.com": "minlength: 8; maxlength: 20; max-consecutive: 4; required: lower, upper; required: digit; allowed: [%&_?#=];", - "anatel.gov.br": "minlength: 6; maxlength: 15; allowed: lower, upper, digit;", - "ancestry.com": "minlength: 8; required: lower; required: upper; required: digit; required: [-!\"#$%&'()*+,./:;<=>?@[^_`{|}~]];", - "angieslist.com": "minlength: 6; maxlength: 15;", - "anthem.com": "minlength: 8; maxlength: 20; max-consecutive: 3; required: lower, upper; required: digit; allowed: [!$*?@|];", - "app.digio.in": "minlength: 8; maxlength: 15;", - "app.parkmobile.io": "minlength: 8; maxlength: 25; required: lower; required: upper; required: digit; required: [!@#$%^&];", - "apple.com": "minlength: 8; maxlength: 63; required: lower; required: upper; required: digit; allowed: ascii-printable;", - "artscyclery.com": "minlength: 6; maxlength: 19;", - "astonmartinf1.com": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; allowed: special;", - "autify.com": "minlength: 8; required: lower; required: upper; required: digit; required: [!\"#$%&'()*+,./:;<=>?@[^_`{|}~]];", - "axa.de": "minlength: 8; maxlength: 65; required: lower; required: upper; required: digit; allowed: [-!\"§$%&/()=?;:_+*'#];", - "baidu.com": "minlength: 6; maxlength: 14;", - "bancochile.cl": "minlength: 8; maxlength: 8; required: lower; required: upper; required: digit;", - "bankofamerica.com": "minlength: 8; maxlength: 20; max-consecutive: 3; required: lower; required: upper; required: digit; allowed: [-@#*()+={}/?~;,._];", - "battle.net": "minlength: 8; maxlength: 16; required: lower, upper; allowed: digit, special;", - "bcassessment.ca": "minlength: 8; maxlength: 14;", - "belkin.com": "minlength: 8; required: lower, upper; required: digit; required: [$!@~_,%&];", - "benefitslogin.discoverybenefits.com": "minlength: 10; required: upper; required: digit; required: [!#$%&*?@]; allowed: lower;", - "benjerry.com": "required: upper; required: upper; required: digit; required: digit; required: special; required: special; allowed: lower;", - "bestbuy.com": "minlength: 20; required: lower; required: upper; required: digit; required: special;", - "bhphotovideo.com": "maxlength: 15;", - "billerweb.com": "minlength: 8; max-consecutive: 2; required: digit; required: upper,lower;", - "biovea.com": "maxlength: 19;", - "bitly.com": "minlength: 6; required: lower; required: upper; required: digit; required: [`!@#$%^&*()+~{}'\";:<>?]];", - "bloomingdales.com": "minlength: 7; maxlength: 16; required: lower, upper; required: digit; required: [`!@#$%^&*()+~{}'\";:<>?]];", - "bluesguitarunleashed.com": "allowed: lower, upper, digit, [!$#@];", - "bochk.com": "minlength: 8; maxlength: 12; max-consecutive: 3; required: lower; required: upper; required: digit; allowed: [#$%&()*+,.:;<=>?@_];", - "box.com": "minlength: 6; maxlength: 20; required: lower; required: upper; required: digit; required: digit;", - "brighthorizons.com": "minlength: 8; maxlength: 16;", - "callofduty.com": "minlength: 8; maxlength: 20; max-consecutive: 2; required: lower, upper; required: digit;", - "capitalone.com": "minlength: 8; maxlength: 32; required: lower, upper; required: digit; allowed: [-_./\\@$*&!#];", - "cardbenefitservices.com": "minlength: 7; maxlength: 100; required: lower, upper; required: digit;", - "cb2.com": "minlength: 7; maxlength: 18; required: lower, upper; required: digit;", - "cecredentialtrust.com": "minlength: 12; required: lower; required: upper; required: digit; required: [!#$%&*@^];", - "chase.com": "minlength: 8; maxlength: 32; max-consecutive: 2; required: lower, upper; required: digit; required: [!#$%+/=@~];", - "cigna.co.uk": "minlength: 8; maxlength: 12; required: lower; required: upper; required: digit;", - "cigna.com": "minlength: 8; maxlength: 12; required: upper; required: digit; required: [_!.&@]; allowed: lower;", - "citi.com": "minlength: 6; maxlength: 50; max-consecutive: 2; required: lower, upper; required: digit; allowed: [_!@$]", - "claimlookup.com": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; required: [@#$%^&+=!];", - "claro.com.br": "minlength: 8; required: lower; allowed: upper, digit, [-!@#$%&*_+=<>];", - "clien.net": "minlength: 5; required: lower, upper; required: digit;", - "comcastpaymentcenter.com": "minlength: 8; maxlength: 20; max-consecutive: 2;required: lower, upper; required: digit;", - "comed.com": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; allowed: [-~!@#$%^&*_+=`|(){}[:;\"'<>,.?/\\]];", - "commerzbank.de": "minlength: 5; maxlength: 8; required: lower, upper; required: digit;", - "consorsbank.de": "minlength: 5; maxlength: 5; required: lower, upper, digit;", - "consorsfinanz.de": "minlength: 6; maxlength: 15; allowed: lower, upper, digit, [-.];", - "costco.com": "minlength: 8; maxlength: 20; required: lower, upper; allowed: digit, [-!#$%&'()*+/:;=?@[^_`{|}~]];", - "coursera.com": "minlength: 8; maxlength: 72;", - "cox.com": "minlength: 8; maxlength: 24; required: digit; required: upper,lower; allowed: [!#$%()*@^];", - "crateandbarrel.com": "minlength: 9; maxlength: 64; required: lower; required: upper; required: digit; required: [!\"#$%&()*,.:<>?@^_{|}];", - "cvs.com": "minlength: 8; maxlength: 25; required: lower, upper; required: digit; allowed: [!@#$%^&*()];", - "dailymail.co.uk": "minlength: 5; maxlength: 15;", - "dan.org": "minlength: 8; maxlength: 25; required: lower; required: upper; required: digit; required: [!@$%^&*];", - "danawa.com": "minlength: 8; maxlength: 21; required: lower, upper; required: digit; required: [!@$%^&*];", - "darty.com": "minlength: 8; required: lower; required: upper; required: digit;", - "dbs.com.hk": "minlength: 8; maxlength: 30; required: lower; required: upper; required: digit;", - "decluttr.com": "minlength: 8; maxlength: 45; required: lower; required: upper; required: digit;", - "delta.com": "minlength: 8; maxlength: 20; required: lower; required: upper; required: digit;", - "deutsche-bank.de": "minlength: 5; maxlength: 5; required: lower, upper, digit;", - "devstore.cn": "minlength: 6; maxlength: 12;", - "dickssportinggoods.com": "minlength: 8; required: lower; required: upper; required: digit; required: [!#$%&*?@^];", - "dkb.de": "minlength: 8; maxlength: 38; required: lower, upper; required: digit; allowed: [-äüöÄÜÖß!$%&/()=?+#,.:];", - "dmm.com": "minlength: 4; maxlength: 16; required: lower; required: upper; required: digit;", - "dowjones.com": "maxlength: 15;", - "ea.com": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; allowed: special;", - "easycoop.com": "minlength: 8; required: upper; required: special; allowed: lower, digit;", - "easyjet.com": "minlength: 6; maxlength: 20; required: lower; required: upper; required: digit; required: [-];", - "ebrap.org": "minlength: 15; required: lower; required: lower; required: upper; required: upper; required: digit; required: digit; required: [-!@#$%^&*()_+|~=`{}[:\";'?,./.]]; required: [-!@#$%^&*()_+|~=`{}[:\";'?,./.]];", - "ecompanystore.com": "minlength: 8; maxlength: 16; max-consecutive: 2; required: lower; required: upper; required: digit; required: [#$%*+.=@^_];", - "eddservices.edd.ca.gov": "minlength: 8; maxlength: 12; required: lower; required: upper; required: digit; required: [!@#$%^&*()];", - "empower-retirement.com": "minlength: 8; maxlength: 16;", - "epicgames.com": "minlength: 7; required: lower; required: upper; required: digit; required: [-!\"#$%&'()*+,./:;<=>?@[^_`{|}~]];", - "epicmix.com": "minlength: 8; maxlength: 16;", - "equifax.com": "minlength: 8; maxlength: 20; required: lower; required: upper; required: digit; required: [!$*+@];", - "essportal.excelityglobal.com": "minlength: 6; maxlength: 8; allowed: lower, upper, digit;", - "ettoday.net": "minlength: 6; maxlength: 12;", - "examservice.com.tw": "minlength: 6; maxlength: 8;", - "expertflyer.com": "minlength: 5; maxlength: 16; required: lower, upper; required: digit;", - "extraspace.com": "minlength: 8; maxlength: 20; allowed: lower; required: upper, digit, [!#$%&*?@];", - "ezpassva.com": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; required: special;", - "fc2.com": "minlength: 8; maxlength: 16;", - "fedex.com": "minlength: 8; max-consecutive: 3; required: lower; required: upper; required: digit; allowed: [-!@#$%^&*_+=`|(){}[:;,.?]];", - "fidelity.com": "minlength: 6; maxlength: 20; required: lower; allowed: upper,digit,[!$%'()+,./:;=?@^_|~];", - "flysas.com": "minlength: 8; maxlength: 14; required: lower; required: upper; required: digit; required: [-~!@#$%^&_+=`|(){}[:\"'<>,.?]];", - "fnac.com": "minlength: 8; required: lower; required: upper; required: digit;", - "fuelrewards.com": "minlength: 8; maxlength: 16; allowed: upper,lower,digit,[!#$%@];", - "gamestop.com": "minlength: 8; maxlength: 225; required: lower; required: upper; required: digit; required: [!@#$%];", - "getflywheel.com": "minlength: 7; maxlength: 72;", - "girlscouts.org": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; allowed: [$#!];", - "gmx.net": "minlength: 8; maxlength: 40; allowed: lower, upper, digit, [-<=>~!|()@#{}$%,.?^'&*_+`:;\"[]];", - "google.com": "minlength: 8; allowed: lower, upper, digit, [-!\"#$%&'()*+,./:;<=>?@[^_{|}~]];", - "guardiananytime.com": "minlength: 8; maxlength: 50; max-consecutive: 2; required: lower; required: upper; required: digit, [-~!@#$%^&*_+=`|(){}[:;,.?]];", - "gwl.greatwestlife.com": "minlength: 8; required: lower; required: upper; required: digit; required: [-!#$%_=+<>];", - "hangseng.com": "minlength: 8; maxlength: 30; required: lower; required: upper; required: digit;", - "hawaiianairlines.com": "maxlength: 16;", - "hertz.com": "minlength: 8; maxlength: 30; max-consecutive: 3; required: lower; required: upper; required: digit; required: [#$%^&!@];", - "hetzner.com": "minlength: 8; required: lower; required: upper; required: digit, special;", - "hilton.com": "minlength: 8; maxlength: 32; required: lower; required: upper; required: digit;", - "hkbea.com": "minlength: 8; maxlength: 12; required: lower; required: upper; required: digit;", - "hkexpress.com": "minlength: 8; maxlength: 15; required: lower; required: upper; required: digit; required: special;", - "hotels.com": "minlength: 6; maxlength: 20; required: digit; allowed: lower, upper, [@$!#()&^*%];", - "hotwire.com": "minlength: 6; maxlength: 30; allowed: lower, upper, digit, [-~!@#$%^&*_+=`|(){}[:;\"'<>,.?]];", - "hrblock.com": "minlength: 8; required: lower; required: upper; required: digit; required: [$#%!];", - "hsbc.com.hk": "minlength: 6; maxlength: 30; required: lower; required: upper; required: digit; allowed: ['.@_];", - "hsbc.com.my": "minlength: 8; maxlength: 30; required: lower, upper; required: digit; allowed: [-!$*.=?@_'];", - "hypovereinsbank.de": "minlength: 6; maxlength: 10; required: lower, upper, digit; allowed: [!\"#$%&()*+:;<=>?@[{}~]];", - "hyresbostader.se": "minlength: 6; maxlength: 20; required: lower, upper; required: digit;", - "id.sonyentertainmentnetwork.com": "minlength: 8; maxlength: 30; required: lower, upper; required: digit; allowed: [-!@#^&*=+;:];", - "identitytheft.gov": "allowed: lower, upper, digit, [!#%&*@^];", - "idestination.info": "maxlength: 15;", - "impots.gouv.fr": "minlength: 12; maxlength: 128; required: lower; required: digit; allowed: [-!#$%&*+/=?^_'.{|}];", - "indochino.com": "minlength: 6; maxlength: 15; required: upper; required: digit; allowed: lower, special;", - "internationalsos.com": "required: lower; required: upper; required: digit; required: [@#$%^&+=_];", - "irctc.co.in": "minlength: 8; maxlength: 15; required: lower; required: upper; required: digit; required: [!@#$%^&*()+];", - "irs.gov": "minlength: 8; maxlength: 32; required: lower; required: upper; required: digit; required: [!#$%&*@];", - "jal.co.jp": "minlength: 8; maxlength: 16;", - "japanpost.jp": "minlength: 8; maxlength: 16; required: digit; required: upper,lower;", - "jordancu-onlinebanking.org": "minlength: 6; maxlength: 32; allowed: upper, lower, digit,[-!\"#$%&'()*+,.:;<=>?@[^_`{|}~]];", - "keldoc.com": "minlength: 12; required: lower; required: upper; required: digit; required: [!@#$%^&*];", - "key.harvard.edu": "minlength: 10; maxlength: 100; required: lower; required: upper; required: digit; allowed: [-@_#!&$`%*+()./,;~:{}|?>=<^[']];", - "kfc.ca": "minlength: 6; maxlength: 15; required: lower; required: upper; required: digit; required: [!@#$%&?*];", - "klm.com": "minlength: 8; maxlength: 12;", - "la-z-boy.com": "minlength: 6; maxlength: 15; required: lower, upper; required: digit;", - "ladwp.com": "minlength: 8; maxlength: 20; required: digit; allowed: lower, upper;", - "live.com": "minlength: 8; required: lower; required: upper; required: digit; allowed: [-@_#!&$`%*+()./,;~:{}|?>=<^'[]];", - "lloydsbank.co.uk": "", - "lowes.com": "minlength: 8; maxlength: 12; required: lower, upper; required: digit;", - "lsacsso.b2clogin.com": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit, [-!#$%&*?@^_];", - "lufthansa.com": "minlength: 8; maxlength: 32; required: lower; required: upper; required: digit; required: [!#$%&()*+,./:;<>?@\"_];", - "macys.com": "minlength: 7; maxlength: 16; allowed: lower, upper, digit, [~!@#$%^&*+`(){}[:;\"'<>?]];", - "mailbox.org": "minlength: 8; required: lower; required: upper; required: digit; allowed: [-!$\"%&/()=*+#.,;:@?{}[]];", - "makemytrip.com": "minlength: 8; required: lower; required: upper; required: digit; required: [@$!%*#?&];", - "marriott.com": "minlength: 8; maxlength: 20; required: lower; required: upper; required: digit; allowed: [$!#&@?%=];", - "maybank2u.com.my": "minlength: 8; maxlength: 12; max-consecutive: 2; required: lower; required: upper; required: digit; required: [-~!@#$%^&*_+=`|(){}[:;\"'<>,.?];", - "medicare.gov": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; required: [@!$%^*()];", - "metlife.com": "minlength: 6; maxlength: 20;", - "microsoft.com": "minlength: 8; required: lower; required: upper; required: digit; required: special;", - "minecraft.com": "minlength: 8; required: lower, upper; required: digit; allowed: ascii-printable;", - "mintmobile.com": "minlength: 8; maxlength: 20; required: lower; required: upper; required: digit; required: special; allowed: [!#$%&()*+:;=@[^_`{}~]];", - "mlb.com": "minlength: 8; maxlength: 15; required: lower; required: upper; required: digit; allowed: [!\"#$%&'()*+,./:;<=>?[\\^_`{|}~]];", - "myaccess.dmdc.osd.mil": "minlength: 9; maxlength: 20; required: lower; required: upper; required: digit; allowed: [-@_#!&$`%*+()./,;~:{}|?>=<^'[]];", - "mygoodtogo.com": "minlength: 8; maxlength: 16; required: lower, upper, digit;", - "myhealthrecord.com": "minlength: 8; maxlength: 20; allowed: lower, upper, digit, [_.!$*=];", - "mysubaru.com": "minlength: 8; maxlength: 15; required: lower; required: upper; required: digit; allowed: [!#$%()*+,./:;=?@\\^`~];", - "naver.com": "minlength: 6; maxlength: 16;", - "nelnet.net": "minlength: 8; maxlength: 15; required: lower; required: upper; required: digit, [!@#$&*];", - "netflix.com": "minlength: 4; maxlength: 60; required: lower, upper, digit; allowed: special;", - "netgear.com": "minlength: 6; maxlength: 128; allowed: lower, upper, digit, [!@#$%^&*()];", - "nowinstock.net": "minlength: 6; maxlength: 20; allowed: lower, upper, digit;", - "ototoy.jp": "minlength: 8; allowed: upper,lower,digit,[- .=_];", - "packageconciergeadmin.com": "minlength: 4; maxlength: 4; allowed: digit;", - "paypal.com": "minlength: 8; maxlength: 20; max-consecutive: 3; required: lower, upper; required: digit, [!@#$%^&*()];", - "payvgm.youraccountadvantage.com": "minlength: 8; required: lower; required: upper; required: digit; required: special;", - "pilotflyingj.com": "minlength: 7; required: digit; allowed: lower, upper;", - "pixnet.cc": "minlength: 4; maxlength: 16; allowed: lower, upper;", - "planetary.org": "minlength: 5; maxlength: 20; required: lower; required: upper; required: digit; allowed: ascii-printable;", - "portal.edd.ca.gov": "minlength: 8; required: lower; required: upper; required: digit; required: [!#$%&()*@^];", - "portals.emblemhealth.com": "minlength: 8; required: lower; required: upper; required: digit; required: [!#$%&'()*+,./:;<>?@\\^_`{|}~[]];", - "portlandgeneral.com": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; allowed: [!#$%&*?@];", - "poste.it": "minlength: 8; maxlength: 16; max-consecutive: 2; required: lower; required: upper; required: digit; required: special;", - "posteo.de": "minlength: 8; required: lower; required: upper; required: digit, [-~!#$%&_+=|(){}[:;\"’<>,.? ]];", - "powells.com": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; required: [\"!@#$%^&*(){}[]];", - "premier.ticketek.com.au": "minlength: 6; maxlength: 16;", - "prepaid.bankofamerica.com": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; required: [!@#$%^&*()+~{}'\";:<>?];", - "prestocard.ca": "minlength: 8; required: lower; required: upper; required: digit,[!\"#$%&'()*+,<>?@];", - "propelfuels.com": "minlength: 6; maxlength: 16;", - "qdosstatusreview.com": "minlength: 8; required: lower; required: upper; required: digit; required: [!#$%&@^];", - "questdiagnostics.com": "minlength: 8; maxlength: 30; required: upper, lower; required: digit, [!#$%&()*+<>?@^_~];", - "rejsekort.dk": "minlength: 7; maxlength: 15; required: lower; required: upper; required: digit;", - "renaud-bray.com": "minlength: 8; maxlength: 38; allowed: upper,lower,digit;", - "ring.com": "minlength: 8; required: lower; required: upper; required: digit; required: [!@#$%^&*<>?];", - "riteaid.com": "minlength: 8; maxlength: 15; required: lower; required: upper; required: digit;", - "robinhood.com": "minlength: 10;", - "rogers.com": "minlength: 8; required: lower, upper; required: digit; required: [!@#$];", - "ruc.dk": "minlength: 6; maxlength: 8; required: lower, upper; required: [-!#%&(){}*+;%/<=>?_];", - "runescape.com": "minlength: 5; maxlength: 20; required: lower; required: upper; required: digit;", - "ruten.com.tw": "minlength: 6; maxlength: 15; required: lower, upper;", - "salslimo.com": "minlength: 8; maxlength: 50; required: upper; required: lower; required: digit; required: [!@#$&*];", - "santahelenasaude.com.br": "minlength: 8; maxlength: 15; required: lower; required: upper; required: digit; required: [-!@#$%&*_+=<>];", - "santander.de": "minlength: 8; maxlength: 12; required: lower, upper; required: digit; allowed: [-!#$%&'()*,.:;=?^{}];", - "sbisec.co.jp": "minlength: 10; maxlength: 20; allowed: upper,lower,digit;", - "secure-arborfcu.org": "minlength: 8; maxlength: 15; required: lower; required: upper; required: digit; required: [!#$%&'()+,.:?@[_`~]];", - "secure.orclinic.com": "minlength: 6; maxlength: 15; required: lower; required: digit; allowed: ascii-printable;", - "secure.snnow.ca": "minlength: 7; maxlength: 16; required: digit; allowed: lower, upper;", - "secure.wa.aaa.com": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; allowed: ascii-printable;", - "sephora.com": "minlength: 6; maxlength: 12;", - "serviziconsolari.esteri.it": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; required: special;", - "servizioelettriconazionale.it": "minlength: 8; maxlength: 20; required: lower; required: upper; required: digit; required: [!#$%&*?@^_~];", - "sfwater.org": "minlength: 10; maxlength: 30; required: digit; allowed: lower, upper, [!@#$%*()_+^}{:;?.];", - "signin.ea.com": "minlength: 8; maxlength: 64; required: lower, upper; required: digit; allowed: [-!@#^&*=+;:];", - "southwest.com": "minlength: 8; maxlength: 16; required: upper; required: digit; allowed: lower, [!@#$%^*(),.;:/\\];", - "speedway.com": "minlength: 4; maxlength: 8; required: digit;", - "spirit.com": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; required: [!@#$%^&*()];", - "splunk.com": "minlength: 8; maxlength: 64; required: lower; required: upper; required: digit; required: [-!@#$%&*_+=<>];", - "ssa.gov": "required: lower; required: upper; required: digit; required: [~!@#$%^&*];", - "store.nvidia.com": "minlength: 8; maxlength: 32; required: lower; required: upper; required: digit; required: [-!@#$%^*~:;&><[{}|_+=?]];", - "store.steampowered.com": "minlength: 6; required: lower; required: upper; required: digit; allowed: [~!@#$%^&*];", - "successfactors.eu": "minlength: 8; maxlength: 18; required: lower; required: upper; required: digit,[-!\"#$%&'()*+,.:;<=>?@[^_`{|}~]];", - "sulamericaseguros.com.br": "minlength: 6; maxlength: 6;", - "sunlife.com": "minlength: 8; maxlength: 10; required: digit; required: lower, upper;", - "t-mobile.net": "minlength: 8; maxlength: 16;", - "target.com": "minlength: 8; maxlength: 20; required: lower, upper; required: digit, [-!\"#$%&'()*+,./:;=?@[\\^_`{|}~];", - "telekom-dienste.de": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; required: [#$%&()*+,./<=>?@_{|}~];", - "thameswater.co.uk": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; required: special;", - "training.confluent.io": "minlength: 6; maxlength: 16; required: lower; required: upper; required: digit; allowed: [!#$%*@^_~];", - "twitter.com": "minlength: 8;", - "ubisoft.com": "minlength: 8; maxlength: 16; required: lower; required: upper; required: digit; required: [-]; required: [!@#$%^&*()+];", - "udel.edu": "minlength: 12; maxlength: 30; required: lower; required: upper; required: digit; required: [!@#$%^&*()+];", - "user.ornl.gov": "minlength: 8; maxlength: 30; max-consecutive: 3; required: lower, upper; required: digit; allowed: [!#$%./_];", - "vanguard.com": "minlength: 6; maxlength: 20; required: lower; required: upper; required: digit; required: digit;", - "vanguardinvestor.co.uk": "minlength: 8; maxlength: 50; required: lower; required: upper; required: digit; required: digit;", - "ventrachicago.com": "minlength: 8; required: lower; required: upper; required: digit, [!@#$%^];", - "verizonwireless.com": "minlength: 8; maxlength: 20; required: lower, upper; required: digit; allowed: unicode;", - "vetsfirstchoice.com": "minlength: 8; required: lower; required: upper; required: digit; allowed: [?!@$%^+=&];", - "virginmobile.ca": "minlength: 8; required: lower; required: upper; required: digit; required: [!#$@];", - "visa.com": "minlength: 6; maxlength: 32;", - "visabenefits-auth.axa-assistance.us": "minlength: 8; required: lower; required: upper; required: digit; required: [!\"#$%&()*,.:<>?@^{|}];", - "vivo.com.br": "maxlength: 6; max-consecutive: 3; allowed: digit;", - "walkhighlands.co.uk": "minlength: 9; maxlength: 15; required: lower; required: upper; required: digit; allowed: special;", - "walmart.com": "allowed: lower, upper, digit, [-(~!@#$%^&*_+=`|(){}[:;\"'<>,.?]];", - "waze.com": "minlength: 8; maxlength: 64; required: lower, upper, digit;", - "wccls.org": "minlength: 4; maxlength: 16; allowed: lower, upper, digit;", - "web.de": "minlength: 8; maxlength: 40; allowed: lower, upper, digit, [-<=>~!|()@#{}$%,.?^'&*_+`:;\"[]];", - "wegmans.com": "minlength: 8; required: digit; required: upper,lower; required: [!#$%&*+=?@^];", - "weibo.com": "minlength: 6; maxlength: 16;", - "wsj.com": "minlength: 5; maxlength: 15; required: digit; allowed: lower, upper, [-~!@#$^*_=`|(){}[:;\"'<>,.?]];", - "xfinity.com": "minlength: 8; maxlength: 16; required: lower, upper; required: digit;", - "xvoucher.com": "minlength: 11; required: upper; required: digit; required: [!@#$%&_];", - "yatra.com": "minlength: 8; required: lower; required: upper; required: digit; required: [!#$%&'()+,.:?@[_`~]];", - "zdf.de": "minlength: 8; required: upper; required: digit; allowed: lower, special;", - "zoom.us": "minlength: 8; maxlength: 32; max-consecutive: 6; required: lower; required: upper; required: digit;", -} - -var genRulesExact = map[string]bool{ - "163.com": false, - "1800flowers.com": false, - "access.service.gov.uk": false, - "admiral.com": false, - "ae.com": false, - "aetna.com": false, - "airasia.com": false, - "ajisushionline.com": false, - "aliexpress.com": false, - "alliantcreditunion.com": false, - "allianz.com.br": false, - "americanexpress.com": false, - "anatel.gov.br": false, - "ancestry.com": false, - "angieslist.com": false, - "anthem.com": false, - "app.digio.in": false, - "app.parkmobile.io": false, - "apple.com": false, - "artscyclery.com": false, - "astonmartinf1.com": false, - "autify.com": false, - "axa.de": false, - "baidu.com": false, - "bancochile.cl": false, - "bankofamerica.com": false, - "battle.net": false, - "bcassessment.ca": false, - "belkin.com": false, - "benefitslogin.discoverybenefits.com": false, - "benjerry.com": false, - "bestbuy.com": false, - "bhphotovideo.com": false, - "billerweb.com": false, - "biovea.com": false, - "bitly.com": false, - "bloomingdales.com": false, - "bluesguitarunleashed.com": false, - "bochk.com": false, - "box.com": false, - "brighthorizons.com": false, - "callofduty.com": false, - "capitalone.com": false, - "cardbenefitservices.com": false, - "cb2.com": false, - "cecredentialtrust.com": false, - "chase.com": false, - "cigna.co.uk": false, - "cigna.com": false, - "citi.com": false, - "claimlookup.com": false, - "claro.com.br": false, - "clien.net": false, - "comcastpaymentcenter.com": false, - "comed.com": false, - "commerzbank.de": false, - "consorsbank.de": false, - "consorsfinanz.de": false, - "costco.com": false, - "coursera.com": false, - "cox.com": false, - "crateandbarrel.com": false, - "cvs.com": false, - "dailymail.co.uk": false, - "dan.org": false, - "danawa.com": false, - "darty.com": false, - "dbs.com.hk": false, - "decluttr.com": false, - "delta.com": false, - "deutsche-bank.de": false, - "devstore.cn": false, - "dickssportinggoods.com": false, - "dkb.de": false, - "dmm.com": false, - "dowjones.com": false, - "ea.com": false, - "easycoop.com": false, - "easyjet.com": false, - "ebrap.org": false, - "ecompanystore.com": false, - "eddservices.edd.ca.gov": false, - "empower-retirement.com": false, - "epicgames.com": false, - "epicmix.com": false, - "equifax.com": false, - "essportal.excelityglobal.com": false, - "ettoday.net": false, - "examservice.com.tw": false, - "expertflyer.com": false, - "extraspace.com": false, - "ezpassva.com": false, - "fc2.com": false, - "fedex.com": false, - "fidelity.com": false, - "flysas.com": false, - "fnac.com": false, - "fuelrewards.com": false, - "gamestop.com": false, - "getflywheel.com": false, - "girlscouts.org": false, - "gmx.net": false, - "google.com": false, - "guardiananytime.com": false, - "gwl.greatwestlife.com": false, - "hangseng.com": false, - "hawaiianairlines.com": false, - "hertz.com": false, - "hetzner.com": false, - "hilton.com": false, - "hkbea.com": false, - "hkexpress.com": false, - "hotels.com": false, - "hotwire.com": false, - "hrblock.com": false, - "hsbc.com.hk": false, - "hsbc.com.my": false, - "hypovereinsbank.de": false, - "hyresbostader.se": false, - "id.sonyentertainmentnetwork.com": false, - "identitytheft.gov": false, - "idestination.info": false, - "impots.gouv.fr": false, - "indochino.com": false, - "internationalsos.com": false, - "irctc.co.in": false, - "irs.gov": false, - "jal.co.jp": false, - "japanpost.jp": false, - "jordancu-onlinebanking.org": false, - "keldoc.com": false, - "key.harvard.edu": false, - "kfc.ca": false, - "klm.com": false, - "la-z-boy.com": false, - "ladwp.com": false, - "live.com": false, - "lloydsbank.co.uk": false, - "lowes.com": false, - "lsacsso.b2clogin.com": false, - "lufthansa.com": false, - "macys.com": false, - "mailbox.org": false, - "makemytrip.com": false, - "marriott.com": false, - "maybank2u.com.my": false, - "medicare.gov": false, - "metlife.com": false, - "microsoft.com": false, - "minecraft.com": false, - "mintmobile.com": false, - "mlb.com": false, - "myaccess.dmdc.osd.mil": false, - "mygoodtogo.com": false, - "myhealthrecord.com": false, - "mysubaru.com": false, - "naver.com": false, - "nelnet.net": false, - "netflix.com": false, - "netgear.com": false, - "nowinstock.net": false, - "ototoy.jp": false, - "packageconciergeadmin.com": false, - "paypal.com": false, - "payvgm.youraccountadvantage.com": false, - "pilotflyingj.com": false, - "pixnet.cc": false, - "planetary.org": false, - "portal.edd.ca.gov": false, - "portals.emblemhealth.com": false, - "portlandgeneral.com": false, - "poste.it": false, - "posteo.de": false, - "powells.com": false, - "premier.ticketek.com.au": false, - "prepaid.bankofamerica.com": false, - "prestocard.ca": false, - "propelfuels.com": false, - "qdosstatusreview.com": false, - "questdiagnostics.com": false, - "rejsekort.dk": false, - "renaud-bray.com": false, - "ring.com": false, - "riteaid.com": false, - "robinhood.com": false, - "rogers.com": false, - "ruc.dk": false, - "runescape.com": false, - "ruten.com.tw": false, - "salslimo.com": false, - "santahelenasaude.com.br": false, - "santander.de": false, - "sbisec.co.jp": false, - "secure-arborfcu.org": false, - "secure.orclinic.com": false, - "secure.snnow.ca": false, - "secure.wa.aaa.com": false, - "sephora.com": false, - "serviziconsolari.esteri.it": false, - "servizioelettriconazionale.it": false, - "sfwater.org": false, - "signin.ea.com": false, - "southwest.com": false, - "speedway.com": false, - "spirit.com": false, - "splunk.com": false, - "ssa.gov": false, - "store.nvidia.com": false, - "store.steampowered.com": false, - "successfactors.eu": false, - "sulamericaseguros.com.br": false, - "sunlife.com": false, - "t-mobile.net": false, - "target.com": false, - "telekom-dienste.de": false, - "thameswater.co.uk": false, - "training.confluent.io": false, - "twitter.com": false, - "ubisoft.com": false, - "udel.edu": false, - "user.ornl.gov": false, - "vanguard.com": false, - "vanguardinvestor.co.uk": false, - "ventrachicago.com": false, - "verizonwireless.com": false, - "vetsfirstchoice.com": false, - "virginmobile.ca": false, - "visa.com": false, - "visabenefits-auth.axa-assistance.us": false, - "vivo.com.br": false, - "walkhighlands.co.uk": false, - "walmart.com": false, - "waze.com": false, - "wccls.org": false, - "web.de": false, - "wegmans.com": false, - "weibo.com": false, - "wsj.com": false, - "xfinity.com": false, - "xvoucher.com": false, - "yatra.com": false, - "zdf.de": false, - "zoom.us": false, +var genRules = map[string]Rule{ + "163.com": {Minlen: 6, Maxlen: 16, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "1800flowers.com": {Minlen: 6, Maxlen: 0, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "access.service.gov.uk": {Minlen: 10, Maxlen: 0, Required: []string{"digit", "lower", "special", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "admiral.com": {Minlen: 8, Maxlen: 0, Required: []string{".:", "[- !\"#$&'()*+,.:;<=>?@[^_`{|}~]]", "digit"}, Allowed: []string{"lower", "upper"}, Maxconsec: 0, Exact: false}, + "ae.com": {Minlen: 8, Maxlen: 25, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "aetna.com": {Minlen: 8, Maxlen: 20, Required: []string{"digit", "upper"}, Allowed: []string{"", "lower"}, Maxconsec: 2, Exact: false}, + "airasia.com": {Minlen: 8, Maxlen: 15, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "ajisushionline.com": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[ !#$%&*?@]", "[ !#$%&*?@]"}, Maxconsec: 0, Exact: false}, + "aliexpress.com": {Minlen: 6, Maxlen: 20, Required: []string{}, Allowed: []string{"digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "alliantcreditunion.com": {Minlen: 8, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[!#$*]", "[!#$*]"}, Maxconsec: 3, Exact: false}, + "allianz.com.br": {Minlen: 4, Maxlen: 4, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "americanexpress.com": {Minlen: 8, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[%&_?#=]", "[%&_?#=]"}, Maxconsec: 4, Exact: false}, + "anatel.gov.br": {Minlen: 6, Maxlen: 15, Required: []string{}, Allowed: []string{"digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "ancestry.com": {Minlen: 8, Maxlen: 0, Required: []string{"./:", "[-!\"#$%&'()*+,./:;<=>?@[^_`{|}~]]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "angieslist.com": {Minlen: 6, Maxlen: 15, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "anthem.com": {Minlen: 8, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[!$*?@|]", "[!$*?@|]"}, Maxconsec: 3, Exact: false}, + "app.digio.in": {Minlen: 8, Maxlen: 15, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "app.parkmobile.io": {Minlen: 8, Maxlen: 25, Required: []string{"[!@#$%^&]", "[!@#$%^&]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "apple.com": {Minlen: 8, Maxlen: 63, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"ascii-printable"}, Maxconsec: 0, Exact: false}, + "artscyclery.com": {Minlen: 6, Maxlen: 19, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "astonmartinf1.com": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"special"}, Maxconsec: 0, Exact: false}, + "autify.com": {Minlen: 8, Maxlen: 0, Required: []string{"./:", "[!\"#$%&'()*+,./:;<=>?@[^_`{|}~]]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "axa.de": {Minlen: 8, Maxlen: 65, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[-!\"§$%&/()=?;:_+*'#]"}, Maxconsec: 0, Exact: false}, + "baidu.com": {Minlen: 6, Maxlen: 14, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "bancochile.cl": {Minlen: 8, Maxlen: 8, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "bankofamerica.com": {Minlen: 8, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[-@#*()+={}/?~;,._]"}, Maxconsec: 3, Exact: false}, + "battle.net": {Minlen: 8, Maxlen: 16, Required: []string{"lower", "upper"}, Allowed: []string{"digit", "special"}, Maxconsec: 0, Exact: false}, + "bcassessment.ca": {Minlen: 8, Maxlen: 14, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "belkin.com": {Minlen: 8, Maxlen: 0, Required: []string{"%&]", "[$!@~_,%&]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "benefitslogin.discoverybenefits.com": {Minlen: 10, Maxlen: 0, Required: []string{"[!#$%&*?@]", "[!#$%&*?@]", "digit", "upper"}, Allowed: []string{"lower"}, Maxconsec: 0, Exact: false}, + "benjerry.com": {Minlen: 0, Maxlen: 0, Required: []string{"digit", "digit", "special", "special", "upper", "upper"}, Allowed: []string{"lower"}, Maxconsec: 0, Exact: false}, + "bestbuy.com": {Minlen: 20, Maxlen: 0, Required: []string{"digit", "lower", "special", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "bhphotovideo.com": {Minlen: 0, Maxlen: 15, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "billerweb.com": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 2, Exact: false}, + "biovea.com": {Minlen: 0, Maxlen: 19, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "bitly.com": {Minlen: 6, Maxlen: 0, Required: []string{"[`!@#$%^&*()+~{}'\";:<>?]]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "bloomingdales.com": {Minlen: 7, Maxlen: 16, Required: []string{"[`!@#$%^&*()+~{}'\";:<>?]]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "bluesguitarunleashed.com": {Minlen: 0, Maxlen: 0, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "bochk.com": {Minlen: 8, Maxlen: 12, Required: []string{"digit", "lower", "upper"}, Allowed: []string{".:", "[#$%&()*+,.:;<=>?@_]"}, Maxconsec: 3, Exact: false}, + "box.com": {Minlen: 6, Maxlen: 20, Required: []string{"digit", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "brighthorizons.com": {Minlen: 8, Maxlen: 16, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "callofduty.com": {Minlen: 8, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 2, Exact: false}, + "capitalone.com": {Minlen: 8, Maxlen: 32, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[-_./\\@$*&!#]", "[-_./\\@$*&!#]"}, Maxconsec: 0, Exact: false}, + "cardbenefitservices.com": {Minlen: 7, Maxlen: 100, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "cb2.com": {Minlen: 7, Maxlen: 18, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "cecredentialtrust.com": {Minlen: 12, Maxlen: 0, Required: []string{"[!#$%&*@^]", "[!#$%&*@^]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "chase.com": {Minlen: 8, Maxlen: 32, Required: []string{"[!#$%+/=@~]", "[!#$%+/=@~]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 2, Exact: false}, + "cigna.co.uk": {Minlen: 8, Maxlen: 12, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "cigna.com": {Minlen: 8, Maxlen: 12, Required: []string{"[_!.&@]", "[_!.&@]", "digit", "upper"}, Allowed: []string{"lower"}, Maxconsec: 0, Exact: false}, + "citi.com": {Minlen: 6, Maxlen: 50, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[_!@$]"}, Maxconsec: 2, Exact: false}, + "claimlookup.com": {Minlen: 8, Maxlen: 16, Required: []string{"[@#$%^&+=!]", "[@#$%^&+=!]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "claro.com.br": {Minlen: 8, Maxlen: 0, Required: []string{"lower"}, Allowed: []string{"", "digit", "upper"}, Maxconsec: 0, Exact: false}, + "clien.net": {Minlen: 5, Maxlen: 0, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "collectivehealth.com": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "comcastpaymentcenter.com": {Minlen: 8, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 2, Exact: false}, + "comed.com": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[-~!@#$%^&*_+=`|(){}[:;\"'<>,.?/\\]]"}, Maxconsec: 0, Exact: false}, + "commerzbank.de": {Minlen: 5, Maxlen: 8, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "consorsbank.de": {Minlen: 5, Maxlen: 5, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "consorsfinanz.de": {Minlen: 6, Maxlen: 15, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "costco.com": {Minlen: 8, Maxlen: 20, Required: []string{"lower", "upper"}, Allowed: []string{"", "digit"}, Maxconsec: 0, Exact: false}, + "coursera.com": {Minlen: 8, Maxlen: 72, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "cox.com": {Minlen: 8, Maxlen: 24, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[!#$%()*@^]", "[!#$%()*@^]"}, Maxconsec: 0, Exact: false}, + "crateandbarrel.com": {Minlen: 9, Maxlen: 64, Required: []string{".:<>?@^_{|}]", "[!\"#$%&()*,.:<>?@^_{|}]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "cvs.com": {Minlen: 8, Maxlen: 25, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[!@#$%^&*()]", "[!@#$%^&*()]"}, Maxconsec: 0, Exact: false}, + "dailymail.co.uk": {Minlen: 5, Maxlen: 15, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "dan.org": {Minlen: 8, Maxlen: 25, Required: []string{"[!@$%^&*]", "[!@$%^&*]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "danawa.com": {Minlen: 8, Maxlen: 21, Required: []string{"[!@$%^&*]", "[!@$%^&*]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "darty.com": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "dbs.com.hk": {Minlen: 8, Maxlen: 30, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "decluttr.com": {Minlen: 8, Maxlen: 45, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "delta.com": {Minlen: 8, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "deutsche-bank.de": {Minlen: 5, Maxlen: 5, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "devstore.cn": {Minlen: 6, Maxlen: 12, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "dickssportinggoods.com": {Minlen: 8, Maxlen: 0, Required: []string{"[!#$%&*?@^]", "[!#$%&*?@^]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "dkb.de": {Minlen: 8, Maxlen: 38, Required: []string{"digit", "lower", "upper"}, Allowed: []string{".:]", "[-äüöÄÜÖß!$%&/()=?+#,.:]"}, Maxconsec: 0, Exact: false}, + "dmm.com": {Minlen: 4, Maxlen: 16, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "dowjones.com": {Minlen: 0, Maxlen: 15, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "ea.com": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"special"}, Maxconsec: 0, Exact: false}, + "easycoop.com": {Minlen: 8, Maxlen: 0, Required: []string{"special", "upper"}, Allowed: []string{"digit", "lower"}, Maxconsec: 0, Exact: false}, + "easyjet.com": {Minlen: 6, Maxlen: 20, Required: []string{"[-]", "[-]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "ebrap.org": {Minlen: 15, Maxlen: 0, Required: []string{"[-!@#$%^&*()_+|~=`{}[:\";'?,./.]]; required: [-!@#$%^&*()_+|~=`{}[:\";'?,./.]]", "digit", "digit", "lower", "lower", "upper", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "ecompanystore.com": {Minlen: 8, Maxlen: 16, Required: []string{"[#$%*+.=@^_]", "[#$%*+.=@^_]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 2, Exact: false}, + "eddservices.edd.ca.gov": {Minlen: 8, Maxlen: 12, Required: []string{"[!@#$%^&*()]", "[!@#$%^&*()]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "empower-retirement.com": {Minlen: 8, Maxlen: 16, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "epicgames.com": {Minlen: 7, Maxlen: 0, Required: []string{"./:", "[-!\"#$%&'()*+,./:;<=>?@[^_`{|}~]]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "epicmix.com": {Minlen: 8, Maxlen: 16, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "equifax.com": {Minlen: 8, Maxlen: 20, Required: []string{"[!$*+@]", "[!$*+@]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "essportal.excelityglobal.com": {Minlen: 6, Maxlen: 8, Required: []string{}, Allowed: []string{"digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "ettoday.net": {Minlen: 6, Maxlen: 12, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "examservice.com.tw": {Minlen: 6, Maxlen: 8, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "expertflyer.com": {Minlen: 5, Maxlen: 16, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "extraspace.com": {Minlen: 8, Maxlen: 20, Required: []string{"", "digit", "upper"}, Allowed: []string{"lower"}, Maxconsec: 0, Exact: false}, + "ezpassva.com": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "lower", "special", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "fc2.com": {Minlen: 8, Maxlen: 16, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "fedex.com": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[-!@#$%^&*_+=`|(){}[:;,.?]]"}, Maxconsec: 3, Exact: false}, + "fidelity.com": {Minlen: 6, Maxlen: 20, Required: []string{"lower"}, Allowed: []string{"", "digit", "upper"}, Maxconsec: 0, Exact: false}, + "flysas.com": {Minlen: 8, Maxlen: 14, Required: []string{".?]]", "[-~!@#$%^&_+=`|(){}[:\"'<>,.?]]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "fnac.com": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "fuelrewards.com": {Minlen: 8, Maxlen: 16, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "gamestop.com": {Minlen: 8, Maxlen: 225, Required: []string{"[!@#$%]", "[!@#$%]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "getflywheel.com": {Minlen: 7, Maxlen: 72, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "girlscouts.org": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[$#!]", "[$#!]"}, Maxconsec: 0, Exact: false}, + "gmx.net": {Minlen: 8, Maxlen: 40, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "google.com": {Minlen: 8, Maxlen: 0, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "guardiananytime.com": {Minlen: 8, Maxlen: 50, Required: []string{"", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 2, Exact: false}, + "gwl.greatwestlife.com": {Minlen: 8, Maxlen: 0, Required: []string{"[-!#$%_=+<>]", "[-!#$%_=+<>]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "hangseng.com": {Minlen: 8, Maxlen: 30, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "hawaiianairlines.com": {Minlen: 0, Maxlen: 16, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "hertz.com": {Minlen: 8, Maxlen: 30, Required: []string{"[#$%^&!@]", "[#$%^&!@]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 3, Exact: false}, + "hetzner.com": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "lower", "special", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "hilton.com": {Minlen: 8, Maxlen: 32, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "hkbea.com": {Minlen: 8, Maxlen: 12, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "hkexpress.com": {Minlen: 8, Maxlen: 15, Required: []string{"digit", "lower", "special", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "hotels.com": {Minlen: 6, Maxlen: 20, Required: []string{"digit"}, Allowed: []string{"", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "hotwire.com": {Minlen: 6, Maxlen: 30, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "hrblock.com": {Minlen: 8, Maxlen: 0, Required: []string{"[$#%!]", "[$#%!]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "hsbc.com.hk": {Minlen: 6, Maxlen: 30, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"['.@_]", "['.@_]"}, Maxconsec: 0, Exact: false}, + "hsbc.com.my": {Minlen: 8, Maxlen: 30, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[-!$*.=?@_']", "[-!$*.=?@_']"}, Maxconsec: 0, Exact: false}, + "hypovereinsbank.de": {Minlen: 6, Maxlen: 10, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[!\"#$%&()*+:;<=>?@[{}~]]"}, Maxconsec: 0, Exact: false}, + "hyresbostader.se": {Minlen: 6, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "id.sonyentertainmentnetwork.com": {Minlen: 8, Maxlen: 30, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[-!@#^&*=+;:]"}, Maxconsec: 0, Exact: false}, + "identitytheft.gov": {Minlen: 0, Maxlen: 0, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "idestination.info": {Minlen: 0, Maxlen: 15, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "impots.gouv.fr": {Minlen: 12, Maxlen: 128, Required: []string{"digit", "lower"}, Allowed: []string{"[-!#$%&*+/=?^_'.{|}]", "[-!#$%&*+/=?^_'.{|}]"}, Maxconsec: 0, Exact: false}, + "indochino.com": {Minlen: 6, Maxlen: 15, Required: []string{"digit", "upper"}, Allowed: []string{"lower", "special"}, Maxconsec: 0, Exact: false}, + "internationalsos.com": {Minlen: 0, Maxlen: 0, Required: []string{"[@#$%^&+=_]", "[@#$%^&+=_]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "irctc.co.in": {Minlen: 8, Maxlen: 15, Required: []string{"[!@#$%^&*()+]", "[!@#$%^&*()+]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "irs.gov": {Minlen: 8, Maxlen: 32, Required: []string{"[!#$%&*@]", "[!#$%&*@]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "jal.co.jp": {Minlen: 8, Maxlen: 16, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "japanpost.jp": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "jordancu-onlinebanking.org": {Minlen: 6, Maxlen: 32, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "keldoc.com": {Minlen: 12, Maxlen: 0, Required: []string{"[!@#$%^&*]", "[!@#$%^&*]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "key.harvard.edu": {Minlen: 10, Maxlen: 100, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"", "[-@_#!&$`%*+()./,;~:{}|?>=<^[']]"}, Maxconsec: 0, Exact: false}, + "kfc.ca": {Minlen: 6, Maxlen: 15, Required: []string{"[!@#$%&?*]", "[!@#$%&?*]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "klm.com": {Minlen: 8, Maxlen: 12, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "la-z-boy.com": {Minlen: 6, Maxlen: 15, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "ladwp.com": {Minlen: 8, Maxlen: 20, Required: []string{"digit"}, Allowed: []string{"lower", "upper"}, Maxconsec: 0, Exact: false}, + "live.com": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"", "[-@_#!&$`%*+()./,;~:{}|?>=<^'[]]"}, Maxconsec: 0, Exact: false}, + "lloydsbank.co.uk": {Minlen: 8, Maxlen: 15, Required: []string{"digit", "lower"}, Allowed: []string{"upper"}, Maxconsec: 0, Exact: false}, + "lowes.com": {Minlen: 8, Maxlen: 12, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "lsacsso.b2clogin.com": {Minlen: 8, Maxlen: 16, Required: []string{"", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "lufthansa.com": {Minlen: 8, Maxlen: 32, Required: []string{"./:", "[!#$%&()*+,./:;<>?@\"_]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "macys.com": {Minlen: 7, Maxlen: 16, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "mailbox.org": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"", "[-!$\"%&/()=*+#.,;:@?{}[]]"}, Maxconsec: 0, Exact: false}, + "makemytrip.com": {Minlen: 8, Maxlen: 0, Required: []string{"[@$!%*#?&]", "[@$!%*#?&]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "marriott.com": {Minlen: 8, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[$!#&@?%=]", "[$!#&@?%=]"}, Maxconsec: 0, Exact: false}, + "maybank2u.com.my": {Minlen: 8, Maxlen: 12, Required: []string{"[-~!@#$%^&*_+=`|(){}[:;\"'<>,.?]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 2, Exact: false}, + "medicare.gov": {Minlen: 8, Maxlen: 16, Required: []string{"[@!$%^*()]", "[@!$%^*()]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "metlife.com": {Minlen: 6, Maxlen: 20, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "microsoft.com": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "lower", "special", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "minecraft.com": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"ascii-printable"}, Maxconsec: 0, Exact: false}, + "mintmobile.com": {Minlen: 8, Maxlen: 20, Required: []string{"digit", "lower", "special", "upper"}, Allowed: []string{"[!#$%&()*+:;=@[^_`{}~]]"}, Maxconsec: 0, Exact: false}, + "mlb.com": {Minlen: 8, Maxlen: 15, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"./:", "[!\"#$%&'()*+,./:;<=>?[\\^_`{|}~]]"}, Maxconsec: 0, Exact: false}, + "mpv.tickets.com": {Minlen: 8, Maxlen: 15, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "myaccess.dmdc.osd.mil": {Minlen: 9, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"", "[-@_#!&$`%*+()./,;~:{}|?>=<^'[]]"}, Maxconsec: 0, Exact: false}, + "mygoodtogo.com": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "myhealthrecord.com": {Minlen: 8, Maxlen: 20, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "mysubaru.com": {Minlen: 8, Maxlen: 15, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"./:", "[!#$%()*+,./:;=?@\\^`~]"}, Maxconsec: 0, Exact: false}, + "naver.com": {Minlen: 6, Maxlen: 16, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "nelnet.net": {Minlen: 8, Maxlen: 15, Required: []string{"", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "netflix.com": {Minlen: 4, Maxlen: 60, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"special"}, Maxconsec: 0, Exact: false}, + "netgear.com": {Minlen: 6, Maxlen: 128, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "nowinstock.net": {Minlen: 6, Maxlen: 20, Required: []string{}, Allowed: []string{"digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "order.wendys.com": {Minlen: 6, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[!#$%&()*+/=?^_{}]", "[!#$%&()*+/=?^_{}]"}, Maxconsec: 0, Exact: false}, + "ototoy.jp": {Minlen: 8, Maxlen: 0, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "packageconciergeadmin.com": {Minlen: 4, Maxlen: 4, Required: []string{}, Allowed: []string{"digit"}, Maxconsec: 0, Exact: false}, + "paypal.com": {Minlen: 8, Maxlen: 20, Required: []string{"", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 3, Exact: false}, + "payvgm.youraccountadvantage.com": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "lower", "special", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "pilotflyingj.com": {Minlen: 7, Maxlen: 0, Required: []string{"digit"}, Allowed: []string{"lower", "upper"}, Maxconsec: 0, Exact: false}, + "pixnet.cc": {Minlen: 4, Maxlen: 16, Required: []string{}, Allowed: []string{"lower", "upper"}, Maxconsec: 0, Exact: false}, + "planetary.org": {Minlen: 5, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"ascii-printable"}, Maxconsec: 0, Exact: false}, + "portal.edd.ca.gov": {Minlen: 8, Maxlen: 0, Required: []string{"[!#$%&()*@^]", "[!#$%&()*@^]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "portals.emblemhealth.com": {Minlen: 8, Maxlen: 0, Required: []string{"./:", "[!#$%&'()*+,./:;<>?@\\^_`{|}~[]]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "portlandgeneral.com": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[!#$%&*?@]", "[!#$%&*?@]"}, Maxconsec: 0, Exact: false}, + "poste.it": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "lower", "special", "upper"}, Allowed: []string{}, Maxconsec: 2, Exact: false}, + "posteo.de": {Minlen: 8, Maxlen: 0, Required: []string{"", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "powells.com": {Minlen: 8, Maxlen: 16, Required: []string{"[\"!@#$%^&*(){}[]]", "[\"!@#$%^&*(){}[]]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "premier.ticketek.com.au": {Minlen: 6, Maxlen: 16, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "prepaid.bankofamerica.com": {Minlen: 8, Maxlen: 16, Required: []string{"[!@#$%^&*()+~{}'\";:<>?]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "prestocard.ca": {Minlen: 8, Maxlen: 0, Required: []string{"", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "propelfuels.com": {Minlen: 6, Maxlen: 16, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "qdosstatusreview.com": {Minlen: 8, Maxlen: 0, Required: []string{"[!#$%&@^]", "[!#$%&@^]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "questdiagnostics.com": {Minlen: 8, Maxlen: 30, Required: []string{"", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "rejsekort.dk": {Minlen: 7, Maxlen: 15, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "renaud-bray.com": {Minlen: 8, Maxlen: 38, Required: []string{}, Allowed: []string{"digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "ring.com": {Minlen: 8, Maxlen: 0, Required: []string{"[!@#$%^&*<>?]", "[!@#$%^&*<>?]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "riteaid.com": {Minlen: 8, Maxlen: 15, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "robinhood.com": {Minlen: 10, Maxlen: 0, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "rogers.com": {Minlen: 8, Maxlen: 0, Required: []string{"[!@#$]", "[!@#$]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "ruc.dk": {Minlen: 6, Maxlen: 8, Required: []string{"[-!#%&(){}*+;%/<=>?_]", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "runescape.com": {Minlen: 5, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "ruten.com.tw": {Minlen: 6, Maxlen: 15, Required: []string{"lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "salslimo.com": {Minlen: 8, Maxlen: 50, Required: []string{"[!@#$&*]", "[!@#$&*]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "santahelenasaude.com.br": {Minlen: 8, Maxlen: 15, Required: []string{"[-!@#$%&*_+=<>]", "[-!@#$%&*_+=<>]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "santander.de": {Minlen: 8, Maxlen: 12, Required: []string{"digit", "lower", "upper"}, Allowed: []string{".:", "[-!#$%&'()*,.:;=?^{}]"}, Maxconsec: 0, Exact: false}, + "sbisec.co.jp": {Minlen: 10, Maxlen: 20, Required: []string{}, Allowed: []string{"digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "secure-arborfcu.org": {Minlen: 8, Maxlen: 15, Required: []string{".:?@[_`~]]", "[!#$%&'()+,.:?@[_`~]]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "secure.orclinic.com": {Minlen: 6, Maxlen: 15, Required: []string{"digit", "lower"}, Allowed: []string{"ascii-printable"}, Maxconsec: 0, Exact: false}, + "secure.snnow.ca": {Minlen: 7, Maxlen: 16, Required: []string{"digit"}, Allowed: []string{"lower", "upper"}, Maxconsec: 0, Exact: false}, + "secure.wa.aaa.com": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"ascii-printable"}, Maxconsec: 0, Exact: false}, + "sephora.com": {Minlen: 6, Maxlen: 12, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "serviziconsolari.esteri.it": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "lower", "special", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "servizioelettriconazionale.it": {Minlen: 8, Maxlen: 20, Required: []string{"[!#$%&*?@^_~]", "[!#$%&*?@^_~]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "sfwater.org": {Minlen: 10, Maxlen: 30, Required: []string{"digit"}, Allowed: []string{"", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "signin.ea.com": {Minlen: 8, Maxlen: 64, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[-!@#^&*=+;:]"}, Maxconsec: 0, Exact: false}, + "southwest.com": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "upper"}, Allowed: []string{"", "lower"}, Maxconsec: 0, Exact: false}, + "speedway.com": {Minlen: 4, Maxlen: 8, Required: []string{"digit"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "spirit.com": {Minlen: 8, Maxlen: 16, Required: []string{"[!@#$%^&*()]", "[!@#$%^&*()]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "splunk.com": {Minlen: 8, Maxlen: 64, Required: []string{"[-!@#$%&*_+=<>]", "[-!@#$%&*_+=<>]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "ssa.gov": {Minlen: 0, Maxlen: 0, Required: []string{"[~!@#$%^&*]", "[~!@#$%^&*]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "store.nvidia.com": {Minlen: 8, Maxlen: 32, Required: []string{"[-!@#$%^*~:;&><[{}|_+=?]]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "store.steampowered.com": {Minlen: 6, Maxlen: 0, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[~!@#$%^&*]", "[~!@#$%^&*]"}, Maxconsec: 0, Exact: false}, + "successfactors.eu": {Minlen: 8, Maxlen: 18, Required: []string{"", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "sulamericaseguros.com.br": {Minlen: 6, Maxlen: 6, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "sunlife.com": {Minlen: 8, Maxlen: 10, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "t-mobile.net": {Minlen: 8, Maxlen: 16, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "target.com": {Minlen: 8, Maxlen: 20, Required: []string{"", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "telekom-dienste.de": {Minlen: 8, Maxlen: 16, Required: []string{"./<=>?@_{|}~]", "[#$%&()*+,./<=>?@_{|}~]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "thameswater.co.uk": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "lower", "special", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "training.confluent.io": {Minlen: 6, Maxlen: 16, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[!#$%*@^_~]", "[!#$%*@^_~]"}, Maxconsec: 0, Exact: false}, + "twitter.com": {Minlen: 8, Maxlen: 0, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "ubisoft.com": {Minlen: 8, Maxlen: 16, Required: []string{"[!@#$%^&*()+]", "[-]", "[-]; required: [!@#$%^&*()+]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "udel.edu": {Minlen: 12, Maxlen: 30, Required: []string{"[!@#$%^&*()+]", "[!@#$%^&*()+]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "user.ornl.gov": {Minlen: 8, Maxlen: 30, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[!#$%./_]", "[!#$%./_]"}, Maxconsec: 3, Exact: false}, + "usps.com": {Minlen: 8, Maxlen: 50, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"./?@]", "[-!\"#&'()+,./?@]"}, Maxconsec: 2, Exact: false}, + "vanguard.com": {Minlen: 6, Maxlen: 20, Required: []string{"digit", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "vanguardinvestor.co.uk": {Minlen: 8, Maxlen: 50, Required: []string{"digit", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "ventrachicago.com": {Minlen: 8, Maxlen: 0, Required: []string{"", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "verizonwireless.com": {Minlen: 8, Maxlen: 20, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"unicode"}, Maxconsec: 0, Exact: false}, + "vetsfirstchoice.com": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"[?!@$%^+=&]", "[?!@$%^+=&]"}, Maxconsec: 0, Exact: false}, + "virginmobile.ca": {Minlen: 8, Maxlen: 0, Required: []string{"[!#$@]", "[!#$@]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "visa.com": {Minlen: 6, Maxlen: 32, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "visabenefits-auth.axa-assistance.us": {Minlen: 8, Maxlen: 0, Required: []string{".:<>?@^{|}]", "[!\"#$%&()*,.:<>?@^{|}]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "vivo.com.br": {Minlen: 0, Maxlen: 6, Required: []string{}, Allowed: []string{"digit"}, Maxconsec: 3, Exact: false}, + "walkhighlands.co.uk": {Minlen: 9, Maxlen: 15, Required: []string{"digit", "lower", "upper"}, Allowed: []string{"special"}, Maxconsec: 0, Exact: false}, + "walmart.com": {Minlen: 0, Maxlen: 0, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "waze.com": {Minlen: 8, Maxlen: 64, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "wccls.org": {Minlen: 4, Maxlen: 16, Required: []string{}, Allowed: []string{"digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "web.de": {Minlen: 8, Maxlen: 40, Required: []string{}, Allowed: []string{"", "digit", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "wegmans.com": {Minlen: 8, Maxlen: 0, Required: []string{"[!#$%&*+=?@^]", "[!#$%&*+=?@^]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "weibo.com": {Minlen: 6, Maxlen: 16, Required: []string{}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "wsj.com": {Minlen: 5, Maxlen: 15, Required: []string{"digit"}, Allowed: []string{"", "lower", "upper"}, Maxconsec: 0, Exact: false}, + "xfinity.com": {Minlen: 8, Maxlen: 16, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "xvoucher.com": {Minlen: 11, Maxlen: 0, Required: []string{"[!@#$%&_]", "[!@#$%&_]", "digit", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "yatra.com": {Minlen: 8, Maxlen: 0, Required: []string{".:?@[_`~]]", "[!#$%&'()+,.:?@[_`~]]", "digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 0, Exact: false}, + "zdf.de": {Minlen: 8, Maxlen: 0, Required: []string{"digit", "upper"}, Allowed: []string{"lower", "special"}, Maxconsec: 0, Exact: false}, + "zoom.us": {Minlen: 8, Maxlen: 32, Required: []string{"digit", "lower", "upper"}, Allowed: []string{}, Maxconsec: 6, Exact: false}, } diff --git a/pkg/qrcon/qrcon.go b/pkg/qrcon/qrcon.go index cf7ec560e0..187364de62 100644 --- a/pkg/qrcon/qrcon.go +++ b/pkg/qrcon/qrcon.go @@ -3,9 +3,9 @@ package qrcon import ( - "bytes" "fmt" "image/color" + "strings" "github.com/skip2/go-qrcode" ) @@ -22,23 +22,24 @@ func QRCode(content string) (string, error) { if err != nil { return "", err } - buf := bytes.Buffer{} + + var sb strings.Builder i := q.Image(0) b := i.Bounds() for x := b.Min.X; x < b.Max.X; x++ { for y := b.Min.Y; y < b.Max.Y; y++ { col := i.At(x, y) if sameColor(col, q.ForegroundColor) { - _, _ = buf.WriteString(black) + _, _ = sb.WriteString(black) } else if sameColor(col, q.BackgroundColor) { - _, _ = buf.WriteString(white) + _, _ = sb.WriteString(white) } else { return "", fmt.Errorf("unexpected color at (%d,%d): %+v", x, y, col) } } - _, _ = buf.WriteString("\n") + _, _ = sb.WriteString("\n") } - return buf.String(), nil + return sb.String(), nil } func sameColor(a color.Color, b color.Color) bool { diff --git a/pkg/tempfile/mount_darwin.go b/pkg/tempfile/mount_darwin.go index d31206f032..8b5726234e 100644 --- a/pkg/tempfile/mount_darwin.go +++ b/pkg/tempfile/mount_darwin.go @@ -66,6 +66,7 @@ func (t *File) mount(ctx context.Context) error { return fmt.Errorf("failed to mount filesystem %s to %s: %w", t.dev, t.dir, err) } + // TODO: why? time.Sleep(100 * time.Millisecond) return nil }