genpass — Secure Password Generator¶
Overview¶
The genpass feature generates random passwords that are simultaneously
strong, hand-typeable, and unambiguous when read aloud. Type genpass <length>
in Alfred and you get 8 candidate passwords of the requested length; hit ⌘C
on any item to copy.
Policy enforced for every accepted password:
Length between
8and32(default12)Contains at least one lowercase letter, one uppercase letter, one digit, and one symbol (from
!%@#&^*)Starts with a letter
Excludes the visually-confusing characters
1,l,I,O,0
Source modules¶
afwf_genpass.genpass— the generator itself. Three public functions:is_valid_password(password)— policy check (four-class + starts-with-letter).random_password(length)— generate one password oflengthchars, rejection-sampling untilis_valid_passwordreturnsTrue.gen_passwords(length)— build anafwf.ScriptFiltercontainingn_password(8) freshly generated passwords.main(query)— Alfred entry point. Parsesqueryas an int in[min_length, max_length]; otherwise shows an error item with an autocomplete hint.
afwf_genpass.constants— definescharset_lower,charset_upper,charset_digits,charset_symbols,charset_banned, the combinedcharset_list,min_length=8,default_length=12,max_length=32,n_password=8, and the UI strings shown in Alfred when the user enters nothing or an invalid value.afwf_genpass.cli— two subcommands wrapgenpass:Command.genpass(query)— Alfred Script Filter; emptyqueryfalls back to"12"; exceptions are caught and rendered as an error item that opens the rotating log file on Enter.Command.genpass_one(length=default_length)— prints exactly one password to stdout, no Alfred JSON. Suitable for shell pipelines.
Alfred workflow definition¶
The Alfred Script Filter node for genpass lives in info.plist, with
keyword=genpass and argumenttype=1 (optional argument). Its script
field invokes:
~/.local/bin/uvx --from "afwf-genpass==X.Y.Z" afwf-genpass genpass --query '{query}'
info.plist
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3<plist version="1.0">
4<dict>
5 <key>bundleid</key>
6 <string>MacHu-GWU.generate-secure-password</string>
7 <key>connections</key>
8 <dict>
9 <key>C9643FA2-6BC2-4020-A2D4-4099AF6D58DE</key>
10 <array/>
11 </dict>
12 <key>createdby</key>
13 <string>Sanhe Hu</string>
14 <key>description</key>
15 <string>Generate a Secure Password made easy</string>
16 <key>disabled</key>
17 <false/>
18 <key>name</key>
19 <string>afwf_genpass</string>
20 <key>objects</key>
21 <array>
22 <dict>
23 <key>config</key>
24 <dict>
25 <key>alfredfiltersresults</key>
26 <false/>
27 <key>alfredfiltersresultsmatchmode</key>
28 <integer>0</integer>
29 <key>argumenttreatemptyqueryasnil</key>
30 <false/>
31 <key>argumenttrimmode</key>
32 <integer>0</integer>
33 <key>argumenttype</key>
34 <integer>1</integer>
35 <key>escaping</key>
36 <integer>68</integer>
37 <key>keyword</key>
38 <string>genpass</string>
39 <key>queuedelaycustom</key>
40 <integer>3</integer>
41 <key>queuedelayimmediatelyinitially</key>
42 <true/>
43 <key>queuedelaymode</key>
44 <integer>1</integer>
45 <key>queuemode</key>
46 <integer>1</integer>
47 <key>runningsubtext</key>
48 <string>please wait ...</string>
49 <key>script</key>
50 <string>~/.local/bin/uvx --from "afwf-genpass==0.1.2" afwf-genpass genpass --query '{query}'
51# ~/Documents/GitHub/afwf_genpass-project/.venv/bin/afwf-genpass genpass --query '{query}'</string>
52 <key>scriptargtype</key>
53 <integer>0</integer>
54 <key>scriptfile</key>
55 <string></string>
56 <key>subtext</key>
57 <string>Generate a secure password</string>
58 <key>title</key>
59 <string>genpass</string>
60 <key>type</key>
61 <integer>0</integer>
62 <key>withspace</key>
63 <true/>
64 </dict>
65 <key>type</key>
66 <string>alfred.workflow.input.scriptfilter</string>
67 <key>uid</key>
68 <string>C9643FA2-6BC2-4020-A2D4-4099AF6D58DE</string>
69 <key>version</key>
70 <integer>3</integer>
71 </dict>
72 <dict>
73 <key>config</key>
74 <dict>
75 <key>alfredfiltersresults</key>
76 <false/>
77 <key>alfredfiltersresultsmatchmode</key>
78 <integer>0</integer>
79 <key>argumenttreatemptyqueryasnil</key>
80 <false/>
81 <key>argumenttrimmode</key>
82 <integer>0</integer>
83 <key>argumenttype</key>
84 <integer>1</integer>
85 <key>escaping</key>
86 <integer>68</integer>
87 <key>keyword</key>
88 <string>genid</string>
89 <key>queuedelaycustom</key>
90 <integer>3</integer>
91 <key>queuedelayimmediatelyinitially</key>
92 <true/>
93 <key>queuedelaymode</key>
94 <integer>1</integer>
95 <key>queuemode</key>
96 <integer>1</integer>
97 <key>runningsubtext</key>
98 <string>please wait ...</string>
99 <key>script</key>
100 <string>~/.local/bin/uvx --from "afwf-genpass==0.1.2" afwf-genpass genid --query '{query}'
101# ~/Documents/GitHub/afwf_genpass-project/.venv/bin/afwf-genpass genid --query '{query}'</string>
102 <key>scriptargtype</key>
103 <integer>0</integer>
104 <key>scriptfile</key>
105 <string></string>
106 <key>subtext</key>
107 <string>Generate Random ID</string>
108 <key>title</key>
109 <string>genid</string>
110 <key>type</key>
111 <integer>0</integer>
112 <key>withspace</key>
113 <true/>
114 </dict>
115 <key>type</key>
116 <string>alfred.workflow.input.scriptfilter</string>
117 <key>uid</key>
118 <string>D5C6FAF4-8EC7-4F6E-842A-50587EDA22A9</string>
119 <key>version</key>
120 <integer>3</integer>
121 </dict>
122 <dict>
123 <key>config</key>
124 <dict>
125 <key>alfredfiltersresults</key>
126 <false/>
127 <key>alfredfiltersresultsmatchmode</key>
128 <integer>0</integer>
129 <key>argumenttreatemptyqueryasnil</key>
130 <false/>
131 <key>argumenttrimmode</key>
132 <integer>0</integer>
133 <key>argumenttype</key>
134 <integer>2</integer>
135 <key>escaping</key>
136 <integer>68</integer>
137 <key>keyword</key>
138 <string>genuuid4</string>
139 <key>queuedelaycustom</key>
140 <integer>3</integer>
141 <key>queuedelayimmediatelyinitially</key>
142 <true/>
143 <key>queuedelaymode</key>
144 <integer>1</integer>
145 <key>queuemode</key>
146 <integer>1</integer>
147 <key>runningsubtext</key>
148 <string>please wait ...</string>
149 <key>script</key>
150 <string>~/.local/bin/uvx --from "afwf-genpass==0.1.2" afwf-genpass genuuid4
151# ~/Documents/GitHub/afwf_genpass-project/.venv/bin/afwf-genpass genuuid4</string>
152 <key>scriptargtype</key>
153 <integer>0</integer>
154 <key>scriptfile</key>
155 <string></string>
156 <key>subtext</key>
157 <string>Generate Random UUID 4</string>
158 <key>title</key>
159 <string>genuuid4</string>
160 <key>type</key>
161 <integer>0</integer>
162 <key>withspace</key>
163 <false/>
164 </dict>
165 <key>type</key>
166 <string>alfred.workflow.input.scriptfilter</string>
167 <key>uid</key>
168 <string>7CF84DAD-33A9-408A-8DA3-107AF4FCC927</string>
169 <key>version</key>
170 <integer>3</integer>
171 </dict>
172 </array>
173 <key>readme</key>
174 <string>This workflow can generate secure password that:
175
176- length is between 8, 32 (you can define it)
177- has at least one lowercase letter
178- has at least one upper letter
179- has at least one digital letter
180- has at least one special character
181- avoid characters like ``1lIoO0`` that is hard to distinguish
182
183Dependencies:
184
185- OS Intel / Arm
186- Python3.7+</string>
187 <key>uidata</key>
188 <dict>
189 <key>7CF84DAD-33A9-408A-8DA3-107AF4FCC927</key>
190 <dict>
191 <key>xpos</key>
192 <real>40</real>
193 <key>ypos</key>
194 <real>240</real>
195 </dict>
196 <key>C9643FA2-6BC2-4020-A2D4-4099AF6D58DE</key>
197 <dict>
198 <key>xpos</key>
199 <real>40</real>
200 <key>ypos</key>
201 <real>30</real>
202 </dict>
203 <key>D5C6FAF4-8EC7-4F6E-842A-50587EDA22A9</key>
204 <dict>
205 <key>xpos</key>
206 <real>40</real>
207 <key>ypos</key>
208 <real>135</real>
209 </dict>
210 </dict>
211 <key>userconfigurationconfig</key>
212 <array/>
213 <key>variablesdontexport</key>
214 <array/>
215 <key>version</key>
216 <string>0.1.1</string>
217 <key>webaddress</key>
218 <string>https://github.com/MacHu-GWU/afwf_genpass-project</string>
219</dict>
220</plist>
Tests¶
tests.test_genpass— covers the policy check, the rejection-sampling generator, theScriptFilterbuilder, and every branch ofmain()(valid length, boundary lengths, empty/whitespace query, non-numeric query, out-of-range length).tests.test_cli— theTestGenpassandTestOneVariantsclasses exercise the CLI wrappers, including thegenpass_onestdout variant.