Commit 9a87d877 authored by setop's avatar setop 🚀
Browse files

use baker for a better CLI experience

code lintered
parent 5530daec
......@@ -9,15 +9,15 @@ Lufi is a web-application allowing client-side encrypted file transfers between
However Lufi works in a web browser, like Firefox or Chormium. When you don't want to run a full-featured graphical web browser on your machine to use it, you need a command line.
**pylufic** is a python implementation of a Lufi CLI. useful for those who already have Python in their environments.
**pylufic** is a python implementation of a Lufi CLI, useful for those who already have Python in their environments.
# How
**pylufic** use the same software libraries as the Javascript version - websocket client and Standford Javascript Cryptography Library (SJCL) - but in their python implementations.
# use
# Use
## install
## Install
Be sure to have Python 3.6+ installed.
......@@ -39,20 +39,23 @@ Pip install requirements (use sudo if not in a venv) :
pip install -r requirements.txt
```
If you want to test libraries :
If you want to test libraries, run :
```
./sjcl-test.py && ./ws-test.py
```
## help
## Run
pylufic uses [baker](https://bitbucket.org/mchaput/baker) library which provide inline help
### Help
```
./pylufic.py
```
## Upload
### Upload
```
./pylufic.py file service_url
......@@ -60,7 +63,7 @@ If you want to test libraries :
You may use "https://framadrop.org/" (consider donation).
## Download
### download
```
./pylufic.py url
......@@ -68,6 +71,16 @@ You may use "https://framadrop.org/" (consider donation).
Be aware a file is opened in the current directory in append mode with the name provided in the metadata of the transfer.
## Delete
### delete
To delete a file use link provided by upload function.
An example using curl :
```
curl -s -S 'https://framadrop.org/d/<shortid>/<token>' | html2text
```
# Limitation
Not yet implemented
**pylufic** handles only one file at a time ; no multi-files upload or download.
#!/usr/bin/env python3
import baker
import sys
import os
from websocket import create_connection
......@@ -10,59 +11,64 @@ from base64 import b64decode, b64encode
MAGIC = "XXMOJOXX"
CHUNK_SIZE = 2*1000*1000
def usage():
print("download with : %s <https://service/r/id#key>" % __file__)
print("upload with : %s <filepath> <https://service/r/>" % __file__)
def upload(filepath, url):
@baker.command(
params={
"filepath": "path to local file to encrypt and upload",
"url": "URL of the Lufi service, eg: https://framadrop.org/",
"delay": "delay after which file is deleted on server, in days",
"del_at_first_view": "delete file after first successful download", })
def upload(filepath, url, delay=None, del_at_first_view=False):
key = b64encode(sjcl.get_random_bytes(32))
size = os.path.getsize(filepath)
(e, r) = divmod(size, CHUNK_SIZE)
totalparts = e + [0,1][r>0]
meta = { "name": filepath.split("/")[-1], "size": size, "total": totalparts, "i": 0 }
totalparts = e + [0, 1][r > 0]
meta = {"name": filepath.split("/")[-1],
"size": size,
"total": totalparts,
"i": 0,
"del_at_first_view": del_at_first_view}
f = open(filepath, "rb")
wsurl = url.replace("http", "ws")+"upload/"
ws = create_connection(wsurl)
for (i, data) in enumerate(iter(lambda: f.read(CHUNK_SIZE), b"")):
meta["part"] = i
data = SJCL().encrypt(b64encode(data), key)
data = SJCL().encrypt(b64encode(data), key) # b64 is unnecessary be kept for compatibility
for k in data.keys():
if isinstance(data[k], bytes): # b64encode produces bytes
if isinstance(data[k], bytes): # b64encode produces bytes
data[k] = data[k].decode("ascii")
ws.send(dumps(meta)+MAGIC+dumps(dumps(data)))
ws.send(payload=dumps(meta)+MAGIC+dumps(dumps(data))) # second dumps is unnecessary be kept for compatibility
result = ws.recv()
print(result, file=sys.stderr)
result = loads(result)
meta["id"] = result["short"]
ws.close()
print(url+"r/"+meta["id"]+"#"+key.decode("ascii"))
print("download_url "+url+"r/"+meta["id"]+"#"+key.decode("ascii"))
print("delete_url "+url+"d/"+meta["id"]+"/"+result["token"])
@baker.command(
params={
"url": "download link given by the upload function", })
def download(url):
[url, key] = url.split('#')
url = url.replace("http", "ws").replace("/r/", "/download/")
ws = create_connection(url)
p=0
t=1
while p<t:
p = 0
t = 1
while p < t:
ws.send('{"part":%d}' % p)
result = ws.recv()
idx = result.find(MAGIC)
meta = loads(result[0:idx])
print(meta, file=sys.stderr)
data = loads(loads(result[idx+len(MAGIC):]))
data = loads(loads(result[idx+len(MAGIC):])) # second loads is unnecessary be kept for compatibility
t = meta["total"]
f = open(meta["name"].split("/")[-1], "ab")
f.write(b64decode(SJCL().decrypt(data, key)))
p+=1
f.write(b64decode(SJCL().decrypt(data, key))) # b64 is unnecessary be kept for compatibility
p += 1
ws.close()
if __name__ == "__main__":
if len(sys.argv) == 1:
usage()
elif len(sys.argv) == 2:
download(sys.argv[1])
elif len(sys.argv) == 3:
upload(sys.argv[1], sys.argv[2])
baker.run()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment