259 lines
6.3 KiB
Plaintext
259 lines
6.3 KiB
Plaintext
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>bundleid</key>
|
|
<string>DELL</string>
|
|
<key>connections</key>
|
|
<dict>
|
|
<key>1260B94B-9181-4C34-8D40-6810254B059E</key>
|
|
<array>
|
|
<dict>
|
|
<key>destinationuid</key>
|
|
<string>6A745F91-F8E2-4F85-81D9-E031FDE3494C</string>
|
|
<key>modifiers</key>
|
|
<integer>0</integer>
|
|
<key>modifiersubtext</key>
|
|
<string></string>
|
|
<key>vitoclose</key>
|
|
<false/>
|
|
</dict>
|
|
</array>
|
|
<key>6599D4CA-1A0C-4D9F-AA4A-B96242444DE3</key>
|
|
<array>
|
|
<dict>
|
|
<key>destinationuid</key>
|
|
<string>1260B94B-9181-4C34-8D40-6810254B059E</string>
|
|
<key>modifiers</key>
|
|
<integer>0</integer>
|
|
<key>modifiersubtext</key>
|
|
<string></string>
|
|
<key>vitoclose</key>
|
|
<false/>
|
|
</dict>
|
|
</array>
|
|
<key>6A745F91-F8E2-4F85-81D9-E031FDE3494C</key>
|
|
<array>
|
|
<dict>
|
|
<key>destinationuid</key>
|
|
<string>3F4C2ACB-DDCD-4DEE-B331-0B7B018EC3D3</string>
|
|
<key>modifiers</key>
|
|
<integer>0</integer>
|
|
<key>modifiersubtext</key>
|
|
<string></string>
|
|
<key>vitoclose</key>
|
|
<false/>
|
|
</dict>
|
|
</array>
|
|
</dict>
|
|
<key>createdby</key>
|
|
<string>Timmy</string>
|
|
<key>description</key>
|
|
<string></string>
|
|
<key>disabled</key>
|
|
<false/>
|
|
<key>name</key>
|
|
<string>無腦生密碼</string>
|
|
<key>objects</key>
|
|
<array>
|
|
<dict>
|
|
<key>config</key>
|
|
<dict>
|
|
<key>autopaste</key>
|
|
<true/>
|
|
<key>clipboardtext</key>
|
|
<string>{query}</string>
|
|
<key>ignoredynamicplaceholders</key>
|
|
<false/>
|
|
<key>transient</key>
|
|
<false/>
|
|
</dict>
|
|
<key>type</key>
|
|
<string>alfred.workflow.output.clipboard</string>
|
|
<key>uid</key>
|
|
<string>6A745F91-F8E2-4F85-81D9-E031FDE3494C</string>
|
|
<key>version</key>
|
|
<integer>3</integer>
|
|
</dict>
|
|
<dict>
|
|
<key>config</key>
|
|
<dict>
|
|
<key>lastpathcomponent</key>
|
|
<false/>
|
|
<key>onlyshowifquerypopulated</key>
|
|
<false/>
|
|
<key>removeextension</key>
|
|
<false/>
|
|
<key>text</key>
|
|
<string>搞定!密碼已經複製到剪貼簿囉。</string>
|
|
<key>title</key>
|
|
<string>無腦生密碼</string>
|
|
</dict>
|
|
<key>type</key>
|
|
<string>alfred.workflow.output.notification</string>
|
|
<key>uid</key>
|
|
<string>3F4C2ACB-DDCD-4DEE-B331-0B7B018EC3D3</string>
|
|
<key>version</key>
|
|
<integer>1</integer>
|
|
</dict>
|
|
<dict>
|
|
<key>config</key>
|
|
<dict>
|
|
<key>argumenttrimmode</key>
|
|
<integer>0</integer>
|
|
<key>argumenttype</key>
|
|
<integer>2</integer>
|
|
<key>fixedorder</key>
|
|
<false/>
|
|
<key>items</key>
|
|
<string>[{"title":"Easy to Read","arg":"easy_to_read"},{"title":"All Characters","arg":"all_characters"}]</string>
|
|
<key>keyword</key>
|
|
<string>pwgen</string>
|
|
<key>matchmode</key>
|
|
<integer>0</integer>
|
|
<key>runningsubtext</key>
|
|
<string></string>
|
|
<key>subtext</key>
|
|
<string></string>
|
|
<key>title</key>
|
|
<string></string>
|
|
<key>withspace</key>
|
|
<false/>
|
|
</dict>
|
|
<key>type</key>
|
|
<string>alfred.workflow.input.listfilter</string>
|
|
<key>uid</key>
|
|
<string>6599D4CA-1A0C-4D9F-AA4A-B96242444DE3</string>
|
|
<key>version</key>
|
|
<integer>1</integer>
|
|
</dict>
|
|
<dict>
|
|
<key>config</key>
|
|
<dict>
|
|
<key>concurrently</key>
|
|
<false/>
|
|
<key>escaping</key>
|
|
<integer>68</integer>
|
|
<key>script</key>
|
|
<string>#!/usr/bin/env -S uv run
|
|
# /// script
|
|
# requires-python = ">=3.12"
|
|
# ///
|
|
|
|
import secrets
|
|
import string
|
|
import sys
|
|
from abc import ABC, abstractmethod
|
|
|
|
# 定義基礎介面 (Optional, 但既然你喜歡結構就做完整點)
|
|
class PasswordGenerator(ABC):
|
|
def __init__(self, length: int = 16):
|
|
self.length = length
|
|
|
|
@property
|
|
@abstractmethod
|
|
def characters(self) -> str:
|
|
pass
|
|
|
|
def generate(self) -> str:
|
|
# 這裡改用 secrets (Cryptographically secure)
|
|
return "".join(secrets.choice(self.characters) for _ in range(self.length))
|
|
|
|
# 實作各種類型
|
|
class EasyToSay(PasswordGenerator):
|
|
"""只使用大小寫字母,不含數字符號"""
|
|
@property
|
|
def characters(self):
|
|
return string.ascii_letters
|
|
|
|
class EasyToRead(PasswordGenerator):
|
|
"""排除容易混淆的字元 (0, O, 1, l)"""
|
|
@property
|
|
def characters(self):
|
|
# 建立排除表
|
|
exclude = str.maketrans('', '', '0O1l')
|
|
chars = string.ascii_letters + string.digits
|
|
return chars.translate(exclude)
|
|
|
|
class AllCharacters(PasswordGenerator):
|
|
"""包含所有符號,最強密碼"""
|
|
@property
|
|
def characters(self):
|
|
return string.ascii_letters + string.digits + string.punctuation
|
|
|
|
# 工廠模式選擇器
|
|
def get_password(style: str, length: int = 16) -> str:
|
|
generators = {
|
|
"easy_to_say": EasyToSay,
|
|
"easy_to_read": EasyToRead,
|
|
"all_characters": AllCharacters,
|
|
}
|
|
|
|
# 預設使用 AllCharacters 以防萬一
|
|
generator_class = generators.get(style, AllCharacters)
|
|
return generator_class(length).generate()
|
|
|
|
if __name__ == "__main__":
|
|
# 接收 Alfred 傳來的參數
|
|
if len(sys.argv) > 1:
|
|
query = sys.argv[1]
|
|
else:
|
|
query = "all_characters"
|
|
|
|
# 產生並輸出 (沒有換行符號,方便直接貼上)
|
|
sys.stdout.write(get_password(query))</string>
|
|
<key>scriptargtype</key>
|
|
<integer>1</integer>
|
|
<key>scriptfile</key>
|
|
<string></string>
|
|
<key>type</key>
|
|
<integer>9</integer>
|
|
</dict>
|
|
<key>type</key>
|
|
<string>alfred.workflow.action.script</string>
|
|
<key>uid</key>
|
|
<string>1260B94B-9181-4C34-8D40-6810254B059E</string>
|
|
<key>version</key>
|
|
<integer>2</integer>
|
|
</dict>
|
|
</array>
|
|
<key>readme</key>
|
|
<string></string>
|
|
<key>uidata</key>
|
|
<dict>
|
|
<key>1260B94B-9181-4C34-8D40-6810254B059E</key>
|
|
<dict>
|
|
<key>xpos</key>
|
|
<real>255</real>
|
|
<key>ypos</key>
|
|
<real>155</real>
|
|
</dict>
|
|
<key>3F4C2ACB-DDCD-4DEE-B331-0B7B018EC3D3</key>
|
|
<dict>
|
|
<key>xpos</key>
|
|
<real>620</real>
|
|
<key>ypos</key>
|
|
<real>155</real>
|
|
</dict>
|
|
<key>6599D4CA-1A0C-4D9F-AA4A-B96242444DE3</key>
|
|
<dict>
|
|
<key>xpos</key>
|
|
<real>80</real>
|
|
<key>ypos</key>
|
|
<real>155</real>
|
|
</dict>
|
|
<key>6A745F91-F8E2-4F85-81D9-E031FDE3494C</key>
|
|
<dict>
|
|
<key>xpos</key>
|
|
<real>430</real>
|
|
<key>ypos</key>
|
|
<real>155</real>
|
|
</dict>
|
|
</dict>
|
|
<key>userconfigurationconfig</key>
|
|
<array/>
|
|
<key>webaddress</key>
|
|
<string></string>
|
|
</dict>
|
|
</plist>
|