Add yt-dlp v2021.09.02
[sunny256-utils.git] / genpasswd
blob3a98614a383e584c5e102a16ddabb20434a6071d
1 #!/usr/bin/python
2 """Generate Password from Salts and Passphrase.
4 The salts come from command line option and the passphrase from stdin.
5 Print ``hash(salts + passphrase)'' for your password.
6 You can generate different passwords for many domains from one passphrase.
8 usage: genpasswd [options] [string...]
10 example:
11 $ genpasswd example.com # domain to login
12 Passphrase:My Passphrase # without echoback
13 Vn/aHPNgXbieJCkSGYiAA7y9GwM # got your password for example.com
15 $ genpasswd example.net # domain to login
16 Passphrase:My Passphrase # without echoback
17 /+/G4MzuaiSo9dHE/c0+GgPi6Nc # got your password for example.net
18 """
20 # Copyright (c) 2009,2012 Satoshi Fukutomi <info@fuktommy.com>.
21 # All rights reserved.
23 # Redistribution and use in source and binary forms, with or without
24 # modification, are permitted provided that the following conditions
25 # are met:
26 # 1. Redistributions of source code must retain the above copyright
27 # notice, this list of conditions and the following disclaimer.
28 # 2. Redistributions in binary form must reproduce the above copyright
29 # notice, this list of conditions and the following disclaimer in the
30 # documentation and/or other materials provided with the distribution.
32 # THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
33 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
36 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 # SUCH DAMAGE.
45 import base64
46 import optparse
47 import hashlib
48 import subprocess
49 import sys
50 import unittest
51 from getpass import getpass
54 def parse_args(argv):
55 """Parse command line argments.
56 """
57 usage = 'usage: %prog [options] [string...]'
58 parser = optparse.OptionParser(usage=usage)
59 parser.add_option('-a', '--alphanum', dest='alphanum_mode',
60 default=False, action='store_true',
61 help='password includes alphabet and number only')
62 parser.add_option('-c', '--clipboard', dest='clipboard_mode',
63 default=False, action='store_true',
64 help='copy password to clipboard (require putclip command)')
65 parser.add_option('-f', '--file', dest='saltfile', metavar='FILE',
66 help='additional salt file')
67 parser.add_option('-s', '--size', type='int', dest='size',
68 help='password size')
69 parser.add_option('--test', action='callback', callback=_test,
70 help='run test and exit')
71 return parser.parse_args(argv)
74 def generate_password(salt, options):
75 """Generate password(hash) from salt.
76 """
77 digest = hashlib.sha1(':'.join(salt)).digest()
78 passwd = base64.encodestring(digest).replace('=', '').strip()
80 if options.alphanum_mode:
81 passwd = passwd.replace('+', '').replace('/', '')
82 if options.size is not None:
83 passwd = passwd[:options.size]
85 return passwd
87 def clipboard_command():
88 """Select clipboard command for platform.
89 """
90 if sys.platform.startswith('linux'):
91 return 'xsel --input --clipboard'
92 elif sys.platform == 'darwin':
93 return 'pbcopy'
94 else:
95 raise Exception('I do not know your clipboard command.')
97 def windows_put_clipboard(string):
98 """Put string to clipboard on Windows.
100 Requires pywin32.
102 import win32clipboard
103 win32clipboard.OpenClipboard()
104 win32clipboard.SetClipboardText(string)
105 win32clipboard.CloseClipboard()
107 def put_clipboard(string):
108 """Put string to clipboard.
110 try:
111 windows_put_clipboard(string)
112 return
113 except ImportError:
114 pass
115 if sys.platform == 'cygwin':
116 open('/dev/clipboard', 'wb').write(string)
117 return
118 cmd = clipboard_command()
119 pipe = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE)
120 pipe.stdin.write(string)
121 pipe.stdin.close()
122 pipe.wait()
124 class GeneratePasswordTest(unittest.TestCase):
125 def test_generate(self):
126 """Default.
128 argv = ['foo', 'bar']
129 options, salt = parse_args(argv)
130 result = generate_password(salt, options)
131 self.assertEquals('VNy+Z9IdXrOUk9Rtia4fQS071t4', result)
133 def test_generate_alpha(self):
134 """Set alpha_num_mode on.
136 argv = ['foo', 'bar', '-a']
137 options, salt = parse_args(argv)
138 result = generate_password(salt, options)
139 self.assertEquals('VNyZ9IdXrOUk9Rtia4fQS071t4', result)
141 def test_generate_size(self):
142 """Set Size.
144 argv = ['foo', 'bar', '-s', '6']
145 options, salt = parse_args(argv)
146 result = generate_password(salt, options)
147 self.assertEquals('VNy+Z9', result)
149 def test_generate_alpha_size(self):
150 """Set size and alpha_num_mode.
152 Password size is set size.
154 argv = ['foo', 'bar', '-a', '-s', '6']
155 options, salt = parse_args(argv)
156 result = generate_password(salt, options)
157 self.assertEquals('VNyZ9I', result)
160 def _test(option, opt_str, value, parser, *args, **kwargs):
161 suite = unittest.TestSuite()
162 suite.addTest(unittest.makeSuite(GeneratePasswordTest))
163 result = unittest.TextTestRunner(verbosity=2).run(suite)
164 if result.errors or result.failures:
165 sys.exit(1)
166 else:
167 sys.exit()
170 def main():
171 options, salt = parse_args(sys.argv[1:])
172 if options.saltfile:
173 salt.append(open(options.saltfile, 'rb').read())
174 passphrase = getpass('Passphrase:')
175 salt.append(passphrase)
176 passwd = generate_password(salt, options)
177 if options.clipboard_mode:
178 print 'put password to clipboard.'
179 put_clipboard(passwd)
180 else:
181 print passwd
184 if __name__ == '__main__':
185 main()