Skip to content

Commit 7cf5fa8

Browse files
committed
Working on python API and tests
1 parent f49be8d commit 7cf5fa8

File tree

3 files changed

+320
-140
lines changed

3 files changed

+320
-140
lines changed

example/end_to_end_example.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ mkdir -p "$TMP_DIR"
88
rm -rf "$TMP_DIR"
99

1010

11-
1211
# Make a git repo and add some public content
1312
DEMO_REPO=$TMP_DIR/repo
1413
mkdir -p "$DEMO_REPO"

tests/test_transcrypt.py

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
"""
2+
Requirements:
3+
pip install gpg_lite
4+
pip install ubelt
5+
"""
6+
import ubelt as ub
7+
import os
8+
9+
SALTED = 'U2FsdGV'
10+
11+
12+
class TranscryptAPI:
13+
default_config = {
14+
'cipher': 'aes-256-cbc',
15+
'password': 'correct horse battery staple',
16+
'digest': 'md5',
17+
'use_pbkdf2': '0',
18+
'salt_method': 'password',
19+
'custom_salt': '',
20+
}
21+
22+
def __init__(self, dpath, config=None, verbose=2, transcript_exe=None):
23+
self.dpath = dpath
24+
self.verbose = verbose
25+
self.transcript_exe = ub.Path(ub.find_exe('transcrypt'))
26+
self.env = {}
27+
self.config = self.default_config.copy()
28+
if config:
29+
self.config.update(config)
30+
31+
def cmd(self, command, shell=False):
32+
return ub.cmd(command, cwd=self.dpath, verbose=self.verbose,
33+
env=self.env, shell=shell)
34+
35+
def login(self):
36+
command = (
37+
"{transcript_exe} -c '{cipher}' -p '{password}' "
38+
"-md '{digest}' --use-pbkdf2 '{use_pbkdf2}' "
39+
"-sm '{salt_method}' "
40+
"-cs '{custom_salt}' "
41+
"-y"
42+
).format(transcript_exe=self.transcript_exe, **self.config)
43+
self.cmd(command)
44+
45+
def logout(self):
46+
self.cmd(f'{self.transcript_exe} -f -y')
47+
48+
def display(self):
49+
self.cmd(f'{self.transcript_exe} -d')
50+
51+
def export_gpg(self, recipient):
52+
self.cmd(f'{self.transcript_exe} --export-gpg "{recipient}"')
53+
self.crypt_dpath = self.cmd('git config --local transcrypt.crypt-dir')['out'] or self.dpath / '.git/crypt'
54+
asc_fpath = (self.crypt_dpath / (recipient + '.asc')).exists()
55+
return asc_fpath
56+
57+
def import_gpg(self, asc_fpath):
58+
command = f"{self.transcript_exe} --import-gpg '{asc_fpath}'"
59+
self.cmd(command)
60+
61+
def show_raw(self, fpath):
62+
return self.cmd(f'{self.transcript_exe} -s {fpath}')['out']
63+
64+
def _manual_hack_info(self):
65+
"""
66+
Info on how to get an env to run a failing command manually
67+
"""
68+
for k, v in self.env.items():
69+
print(f'export {k}={v}')
70+
print(f'cd {self.dpath}')
71+
72+
73+
class TestEnvironment:
74+
75+
def __init__(self, dpath=None, config=None, verbose=2):
76+
if dpath is None:
77+
# import tempfile
78+
# self._tmpdir = tempfile.TemporaryDirectory()
79+
# dpath = self._tmpdir.name
80+
dpath = ub.Path.appdir('transcrypt/tests/test_env')
81+
self.dpath = ub.Path(dpath)
82+
self.gpg_store = None
83+
self.repo_dpath = None
84+
self.verbose = verbose
85+
self.tc = None
86+
self.config = config
87+
88+
def setup(self):
89+
self._setup_gpg()
90+
self._setup_git()
91+
self._setup_transcrypt()
92+
return self
93+
94+
def _setup_gpg(self):
95+
import gpg_lite
96+
self.gpg_home = (self.dpath / 'gpg').ensuredir()
97+
self.gpg_store = gpg_lite.GPGStore(
98+
gnupg_home_dir=self.gpg_home
99+
)
100+
self.gpg_fpr = self.gpg_store.gen_key(
101+
full_name='Emmy Noether',
102+
email='emmy.noether@uni-goettingen.de',
103+
passphrase=None,
104+
key_type='eddsa',
105+
subkey_type='ecdh',
106+
key_curve='Ed25519',
107+
subkey_curve='Curve25519'
108+
)
109+
110+
# Fix GNUPG permissions
111+
dpath = os.environ.get('GNUPGHOME', ub.expandpath('$HOME/.gnupg'))
112+
(self.gpg_home / 'private-keys-v1.d').ensuredir()
113+
# 600 for files and 700 for directories
114+
ub.cmd('find ' + dpath + r' -type f -exec chmod 600 {} \;', shell=True, verbose=self.verbose)
115+
ub.cmd('find ' + dpath + r' -type d -exec chmod 700 {} \;', shell=True, verbose=self.verbose)
116+
117+
def _setup_git(self):
118+
import git
119+
# Make a git repo and add some public content
120+
repo_name = 'demo-repo'
121+
self.repo_dpath = (self.dpath / repo_name).ensuredir()
122+
# self.repo_dpath.delete().ensuredir()
123+
self.repo_dpath.ensuredir()
124+
125+
for content in self.repo_dpath.iterdir():
126+
content.delete()
127+
128+
self.git = git.Git(self.repo_dpath)
129+
self.git.init()
130+
readme_fpath = (self.repo_dpath / 'README.md')
131+
readme_fpath.write_text('content')
132+
self.git.add(readme_fpath)
133+
134+
# Create safe directory that we will encrypt
135+
gitattr_fpath = self.repo_dpath / '.gitattributes'
136+
gitattr_fpath.write_text(ub.codeblock(
137+
'''
138+
safe/* filter=crypt diff=crypt merge=crypt
139+
'''))
140+
self.git.add(gitattr_fpath)
141+
self.git.commit('-am Add initial contents')
142+
self.safe_dpath = (self.repo_dpath / 'safe').ensuredir()
143+
self.secret_fpath = self.safe_dpath / 'secret.txt'
144+
145+
def _setup_transcrypt(self):
146+
self.tc = TranscryptAPI(self.repo_dpath, self.config,
147+
verbose=self.verbose)
148+
err = self.tc.cmd(f'{self.tc.transcript_exe} -d')['err'].strip()
149+
if err != 'transcrypt: the current repository is not configured':
150+
raise AssertionError(f"Got {err}")
151+
self.tc.login()
152+
self.secret_fpath.write_text('secret content')
153+
self.git.add(self.secret_fpath)
154+
self.git.commit('-am add secret')
155+
self.tc.display()
156+
if self.gpg_home is not None:
157+
self.tc.env['GNUPGHOME'] = str(self.gpg_home)
158+
159+
def test_round_trip(self):
160+
content = self.tc.show_raw(self.secret_fpath)
161+
assert content.startswith(SALTED)
162+
assert self.secret_fpath.read_text().startswith('secret content')
163+
self.tc.logout()
164+
assert self.secret_fpath.read_text().startswith(SALTED)
165+
self.tc.login()
166+
assert self.secret_fpath.read_text().startswith('secret content')
167+
168+
def test_export_gpg(self):
169+
self.tc.display()
170+
asc_fpath = self.tc.export_gpg(self.gpg_fpr)
171+
self.tc.logout()
172+
self.tc.import_gpg(asc_fpath)
173+
174+
175+
def run_tests():
176+
"""
177+
CommandLine:
178+
xdoctest -m /home/joncrall/code/transcrypt/tests/test_transcrypt.py run_tests
179+
180+
Example:
181+
>>> import sys, ubelt
182+
>>> sys.path.append(ubelt.expandpath('~/code/transcrypt/tests'))
183+
>>> from test_transcrypt import * # NOQA
184+
>>> self = TestEnvironment()
185+
>>> self.setup()
186+
>>> self.tc._manual_hack_info()
187+
188+
>>> self.test_round_trip()
189+
>>> self.test_export_gpg()
190+
191+
self = TestEnvironment(config={'use_pbkdf2': 1})
192+
self.setup()
193+
self.test_round_trip()
194+
self.test_export_gpg()
195+
"""

0 commit comments

Comments
 (0)