diff --git a/.drone.yml b/.drone.yml index 5ea4ce6..0bea603 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,6 +7,7 @@ pipeline: modules: image: python:3.5 commands: + - rm -rf modules - mkdir -p .pip3 - ./make-modules.sh --cache-dir .pip3 package: @@ -24,7 +25,3 @@ pipeline: - sha256 when: event: tag - clean: - image: kramos/alpine-zip - commands: - - rm -rf modules diff --git a/.gitignore b/.gitignore index 86b519f..6f8ac0d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ modules .pip3 seafile.zip +lib diff --git a/imports/encryptedscreenshot.py b/imports/encryptedscreenshot.py index 128a7ca..0246c7c 100644 --- a/imports/encryptedscreenshot.py +++ b/imports/encryptedscreenshot.py @@ -1,15 +1,23 @@ -import bson#, scrypt +from Crypto.Signature import PKCS1_v1_5 +from Crypto.Hash import SHA256 +import bson # , scrypt from Crypto.Cipher import AES from Crypto.Util import Counter from Crypto.PublicKey import RSA from Crypto.PublicKey import DSA from salsa20 import Salsa20_keystream -import os, struct, time, hashlib, hashlib, random, binascii +import os +import struct +import time +import hashlib +import hashlib +import random +import binascii class EncryptedScreenshot: - def __init__(self, metadata,password=None,id=None,signer=None,password_encryptor=None): + def __init__(self, metadata, password=None, id=None, signer=None, password_encryptor=None): def rand(len): return ''.join( random.choice("1234567890ABCDEFGHIJKLMNOPQRSTUWVXYZabcdefghijklmnopqrstuwvxyz") for _ in range(len)) @@ -24,14 +32,16 @@ class EncryptedScreenshot: self.password_encryptor = password_encryptor def caesar_encrypted_password(self): - caesar_key = reduce(lambda sum,charcode: sum+charcode, map(ord,list(self.id))) + caesar_key = reduce(lambda sum, charcode: sum + + charcode, map(ord, list(self.id))) caesar_plaintext = map(ord, self.password) - caesar_ciphertext = Caesar().encrypt(caesar_plaintext,caesar_key) - return ''.join(map(chr,caesar_ciphertext)) + caesar_ciphertext = Caesar().encrypt(caesar_plaintext, caesar_key) + return ''.join(map(chr, caesar_ciphertext)) def passphrase(self): # new ScryptParameters(64, 8, 1,32, new Uint8List.fromList(new List())) - print("Password units: %s" % (map(ord, self.password.encode("utf-8")),)) + print("Password units: %s" % + (map(ord, self.password.encode("utf-8")),)) sha = hashlib.sha256() sha.update(self.password.encode("utf-8")) return sha.digest() # scrypt.hash(self.password.encode("utf-8"), '', 64, 8, 1, 32) @@ -41,7 +51,8 @@ class EncryptedScreenshot: self.metadata["hash"] = image_digest unencrypted_metadata = bson.dumps(self.metadata) if len(unencrypted_metadata) % 16 != 0: - unencrypted_metadata += b' ' * (16 - len(unencrypted_metadata) % 16) + unencrypted_metadata += b' ' * \ + (16 - len(unencrypted_metadata) % 16) (encryptor, iv) = self.encryptor(len(unencrypted_metadata)) encrypted_metadata = b'' @@ -54,7 +65,7 @@ class EncryptedScreenshot: #print("Unencrypted: %s" % (unencrypted_metadata.encode("hex"))) #print("Password %s" % self.password) - #print(bson.loads(unencrypted_metadata)) + # print(bson.loads(unencrypted_metadata)) fields = { "image": encrypted_image, @@ -64,25 +75,27 @@ class EncryptedScreenshot: } if self.signer is not None: - fields["signature"] = self.signer.signature(encrypted_metadata if self.metadata_encryption else bson.dumps(self.metadata)) + fields["signature"] = self.signer.signature( + encrypted_metadata if self.metadata_encryption else bson.dumps(self.metadata)) if self.password_encryptor is not None: - fields["password"] = self.password_encryptor.encrypt_password(self.password) + fields["password"] = self.password_encryptor.encrypt_password( + self.password) return bson.dumps(fields) - def encryptor(self,length=0): + def encryptor(self, length=0): iv = os.urandom(16) nonce = int(binascii.hexlify(iv), 16) - ctr = Counter.new(128,initial_value = nonce)# initial_value = nonce) + ctr = Counter.new(128, initial_value=nonce) # initial_value = nonce) print("IV: %s" % binascii.hexlify(iv)) cipher = AES.new(self.passphrase(), AES.MODE_CTR, counter=ctr) - #salsa + # salsa # keysstream = bytearray(Salsa20_keystream(length,iv[:8],self.passphrase())) # offset={"offset": 0} def encrypt(data): - #Salsa20 + # Salsa20 # array = bytearray(data) # for i in range(len(array)): # array[i] ^= keysstream[i+offset["offset"]] @@ -109,16 +122,14 @@ class EncryptedScreenshot: binary += encryptor(chunk) return (digest.digest(), iv + binary) -from Crypto.Signature import PKCS1_v1_5 -from Crypto.Hash import SHA256 class Signer: @staticmethod def default(): - return Signer(RSA.importKey("-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----\n"),"PUBLIC") + return Signer(RSA.importKey("-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----\n"), "PUBLIC") - def __init__(self,privateKey,privateKeyId, mode=RSA): + def __init__(self, privateKey, privateKeyId, mode=RSA): self.mode = mode self.privateKeyId = privateKeyId self._signer = PKCS1_v1_5.new(privateKey) @@ -128,7 +139,7 @@ class Signer: digest.update(data) return self._signer.sign(digest) - def signature(self,data): + def signature(self, data): signed = self.sign(data) return {"signed-hash": signed, "signature-algorithm": "SHA-256/%s" % ("RSA" if self.mode == RSA else "DSA"), @@ -138,40 +149,41 @@ class Signer: class EncryptedPassword: - def __init__(self,publicKey,publicKeyId,mode=RSA): + def __init__(self, publicKey, publicKeyId, mode=RSA): assert mode == RSA self.mode = mode self.publicKey = publicKey self.publicKeyId = publicKeyId - def encrypt(self,password): + def encrypt(self, password): return self.publicKey.encrypt(password.encode("utf-8"), os.urandom(32))[0] - def encrypt_password(self,password): - return {"algorithm": unicode( "RSA" if self.mode == RSA else "DSA"), + def encrypt_password(self, password): + return {"algorithm": unicode("RSA" if self.mode == RSA else "DSA"), "key-id": unicode(self.publicKeyId), "password": self.encrypt(password) } + class Caesar: - def __init__(self,charset = map(ord,list("1234567890ABCDEFGHIJKLMNOPQRSTUWVXYZabcdefghijklmnopqrstuwvxyz"))): + def __init__(self, charset=map(ord, list("1234567890ABCDEFGHIJKLMNOPQRSTUWVXYZabcdefghijklmnopqrstuwvxyz"))): self.charset = charset - def encrypt(self,plaintext,key): - if key >= len(self.charset) or key < 0: + def encrypt(self, plaintext, key): + if key >= len(self.charset) or key < 0: key = key % len(self.charset) - def addKey(charcode): + def addKey(charcode): pos = self.charset.index(charcode) if pos + key >= len(self.charset): return self.charset[pos+key - len(self.charset)] else: return self.charset[pos+key] - return map(addKey,plaintext) + return map(addKey, plaintext) - def decrypt(self,ciphertext,key): - return self.encrypt(ciphertext,key*-1) + def decrypt(self, ciphertext, key): + return self.encrypt(ciphertext, key*-1) if __name__ == "__main__": @@ -179,22 +191,26 @@ if __name__ == "__main__": publicKey = "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUF1VEVIVldqdHdGeWRHL1ZtSEtyMQo1cXltSWt3WklhTm5RZUttQnp6bituODdaamRna0VEdENFWVNxM1cxVnhsZ1V3MURoOEtUVHIzSzFMUXdjRGZ4Cjh2ZEFyazk5T1g0bXhxcFlXUmJkZkVRazF3VUQ3Y3RyMkU1ZUtRY0NjYkFsL09LWUZhL1BrWTNLc0J1bnMwNlIKbGY4NXNIU1o3Q2ZpcnFINkZvZWZyWERaVkFKT21yUWhUaC8wcUdsQnkxZjEzYzJhMTJzRk5PbW5jTHM4VnA0Zgp0SnhMcjlHb0U0dnNRdlgvNm9Rdmk3UHFXWW12bHdtVVV2aENQUy9KU0Y4a0N1dm12ZmdjRjhPWE9qMVE2aXRPCkxaRHQ4L1p1WmVvazduUzhKeGhSNzNIekhSNGFIV25xQzhVa0l4MUNSL1Z2bFpocC83Z2JTL3kxRU9SUmFWbE8KM1lUa0YyVU1UdEYyQm9Dc1k1Z2xwZWFsRFY2Rmg5WVp3cTY4QVBiNS9jbGV1WHU4dGViWXBvNXl1d0g5RzhtMApicDdtSXJWVW5hQlBDRS9Xc2o2SEZVTG5pVWk4ME44MTQ5Y00ya0xtbTdjK0pOQzRRVXVwYzNpeTNxeWxxaDFLCkZsVTBTV1BBaW5EYk9EU0hxblBpV1YwSUhqQzltVmVBbU1EamcvNlI3dWFBdWJMejBySnNvL29kazBrZldZTzkKOEQ0M0h2N0MrVEcvSWY5b0U3SmRzZ1NDQ2ZlVHVhS0U1WEgzQzNHZWdjaURPeXI2U2QvMDhLcHJRd3Z5N25acApKSnh6cHlyMk1vSi9uOE82TzRJcUR0NzZFQVp6NzZuVXZKelBYU29VR3k3OTQyUU93eXdwUllCNk5iclZwUFVlCm1VQ3NVdHRVSnpoZ0hVNzBFbHFFMmhzQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=" encrypted = EncryptedScreenshot({"owner": u"test", "format": u"jpg", "title": u"5x5 Red", "timestamp": int(time.time()*1000)}, signer=Signer.default(), - password_encryptor=EncryptedPassword(RSA.importKey(publicKey.decode("base64")),"PUBLIC")) - fixed_id = encrypted.id #"W9u9Zm0u" + password_encryptor=EncryptedPassword(RSA.importKey(publicKey.decode("base64")), "PUBLIC")) + fixed_id = encrypted.id # "W9u9Zm0u" print(len(encrypted.passphrase())) - out = open("/home/marvin/Dokumente/IdeaProjects/EncryptedScreencloud/Frontend/WebApp/web/data/" + fixed_id, 'wb') + out = open( + "/home/marvin/Dokumente/IdeaProjects/EncryptedScreencloud/Frontend/WebApp/web/data/" + fixed_id, 'wb') assembled = encrypted.assemble("5x5red.png") out.write(assembled) b = bson.loads(assembled) del b["image"] print(b) - #print(assembled.encode("base64").replace("\n","") + # print(assembled.encode("base64").replace("\n","") print("http://localhost:8080/#%s%s" % (fixed_id, encrypted.password)) - caesar_key = reduce(lambda sum,charcode: sum+charcode, map(ord,list(fixed_id))) - caesar_plaintext = map(ord,encrypted.password) - caesar_ciphertext = Caesar().encrypt(caesar_plaintext,caesar_key) - assert caesar_plaintext == Caesar().decrypt(caesar_ciphertext,caesar_key) - print("caesar_key=%s %s -> %s" % (caesar_key,encrypted.password,''.join(map(chr,caesar_ciphertext)))) - print("http://localhost:8080/#%s%sC" % (fixed_id, encrypted.caesar_encrypted_password())) + caesar_key = reduce(lambda sum, charcode: sum + + charcode, map(ord, list(fixed_id))) + caesar_plaintext = map(ord, encrypted.password) + caesar_ciphertext = Caesar().encrypt(caesar_plaintext, caesar_key) + assert caesar_plaintext == Caesar().decrypt(caesar_ciphertext, caesar_key) + print("caesar_key=%s %s -> %s" % + (caesar_key, encrypted.password, ''.join(map(chr, caesar_ciphertext)))) + print("http://localhost:8080/#%s%sC" % + (fixed_id, encrypted.caesar_encrypted_password())) print("http://localhost:8080/#%s" % (fixed_id, )) out.close() diff --git a/imports/hashderive.py b/imports/hashderive.py index 93f978f..87d329e 100644 --- a/imports/hashderive.py +++ b/imports/hashderive.py @@ -2,6 +2,7 @@ import hashlib import binascii + class HashDerivedKey: @staticmethod @@ -13,18 +14,20 @@ class HashDerivedKey: assert isinstance(b, bytes) return b ensure_bytes(master) + def derive(seed): ensure_bytes(seed) sha = hashlib.sha256() sha.update(master) sha.update(seed) return sha.digest() - hex = lambda b: binascii.hexlify(b).decode("utf-8") + + def hex(b): return binascii.hexlify(b).decode("utf-8") self.master = master self.master_hex = lambda: hex(master) self.derive = derive self.derive_hex = lambda seed: hex(derive(seed)) - def derive_metadata(self,seed): + def derive_metadata(self, seed): key = self.derive(seed) - return (key,{"key_seed": binascii.hexlify(seed).decode("utf-8")}) + return (key, {"key_seed": binascii.hexlify(seed).decode("utf-8")}) diff --git a/imports/processors.py b/imports/processors.py index a5f7c9b..138d37e 100644 --- a/imports/processors.py +++ b/imports/processors.py @@ -2,101 +2,122 @@ import time from encryptedscreenshot import EncryptedScreenshot, Signer from hashderive import HashDerivedKey -import getpass, os, sys +import getpass +import os +import sys from PythonQt.QtGui import QInputDialog from PythonQt.QtCore import QSettings from seafapi import * + class Processor: - def configure(self,parent): + def name(self): + pass + + def configure(self, parent): pass def is_configured(self): return True - def upload(self,file): + def load_settings(self, settings): pass + def save_settings(self, settings): + pass + + def upload(self, file, name): + pass + + class DummyProcessor(Processor): + def name(self): + return None + def is_configured(self): return False + class DefaultProcessor(Processor): - def __init__(self,seaf_lib,lib_path): + def name(self): + return "default" + + def __init__(self, seaf_lib, lib_path): self.seaf_lib = seaf_lib self.lib_path = lib_path - def upload(self,file,name): - return self.seaf_lib.upload(file,name,self.lib_path).share() + def upload(self, file, name): + return self.seaf_lib.upload(file, name, self.lib_path).share() + class EncryptedProcessor(Processor): - def __init__(self,seaf_lib,lib_path): + def name(self): + return "enc" + + def __init__(self, seaf_lib, lib_path): self.seaf_lib = seaf_lib self.lib_path = lib_path self.host = None self.derived_key = HashDerivedKey(os.urandom(32)) self.load_settings() - def load_settings(self): - settings = QSettings() - settings.beginGroup("uploaders") - settings.beginGroup("seafile") + def load_settings(self, settings=QSettings()): self.host = settings.value("encscreen-url", None) if settings.value("encscreen-derived-key", None): - self.derived_key = HashDerivedKey.from_hex(settings.value("encscreen-derived-key", None)) + self.derived_key = HashDerivedKey.from_hex( + settings.value("encscreen-derived-key", None)) settings.endGroup() settings.endGroup() - def save_settings(self): - settings = QSettings() - settings.beginGroup("uploaders") - settings.beginGroup("seafile") + def save_settings(self, settings=QSettings()): settings.setValue("encscreen-url", self.host) - if self.derived_key: settings.setValue(self.derived_key.master_hex()) + if self.derived_key: + settings.setValue(self.derived_key.master_hex()) settings.endGroup() settings.endGroup() def is_configured(self): return self.host is not None and self.host != "" - def configure(self,parent): - self.host = QInputDialog.getText(parent, 'Encscreen Server Setup', 'Enter server url (ex. https://servertld/s#%id%key):', text=(self.host or "https://screens.shimun.net/s#%id%key")) - master = QInputDialog.getText(parent, 'Encscreen Master Key Setup', 'Enter master key (hex encoded):', text=(self.derived_key.master_hex() if self.derived_key else "")) + def configure(self, parent): + self.host = QInputDialog.getText(parent, 'Encscreen Server Setup', 'Enter server url (ex. https://servertld/s#%id%key):', + text=(self.host or "https://screens.shimun.net/s#%id%key")) + master = QInputDialog.getText(parent, 'Encscreen Master Key Setup', 'Enter master key (hex encoded):', text=( + self.derived_key.master_hex() if self.derived_key else "")) try: self.derived_key = HashDerivedKey.from_hex(master) except: self.derived_key = HashDerivedKey(os.urandom(32)) self.save_settings() - def upload(self,file,name): + def upload(self, file, name): def derive(): seed = os.urandom(16) (_, key_meta) = self.derived_key.derive_metadata(seed) return (self.derived_key.derive_hex(seed)[0:16], key_meta) (key, key_meta) = derive() - enrypted = EncryptedScreenshot(metadata = { + enrypted = EncryptedScreenshot(metadata={ "owner": getpass.getuser(), "format": str(file).split('.')[-1], "title": name, "timestamp": int(time.time() * 1000), "size": os.stat(file).st_size, "public": key_meta - },password=key,signer=Signer.default()) + }, password=key, signer=Signer.default()) tmpHandle = open(file + "c", 'wb') tmpHandle.write(enrypted.assemble(file)) tmpHandle.close() - seaf_file = self.seaf_lib.upload(file + "c",name + ".enc",self.lib_path) + seaf_file = self.seaf_lib.upload( + file + "c", name + ".enc", self.lib_path) if not seaf_file: return seaf_link = seaf_file.share() if seaf_link: id = str(seaf_link).split('/')[-2] - return self.host.replace('%id', id).replace('%key',"%s" % enrypted.password) + return self.host.replace('%id', id).replace('%key', "%s" % enrypted.password) else: return False - - diff --git a/imports/seafapi.py b/imports/seafapi.py index 944b6ce..c8d9353 100644 --- a/imports/seafapi.py +++ b/imports/seafapi.py @@ -1,57 +1,65 @@ -import time, os +import time +import os import requests + class SeafileClient: - def __init__(self,server,username,password=None,token=None): + def __init__(self, server, username, password=None, token=None): self.server = server self.token = token self.session = requests.Session() if token: - self.session.headers.update({'Authorization': "Token %s" % self.token.token}) - self.login = (username,password) + self.session.headers.update( + {'Authorization': "Token %s" % self.token.token}) + self.login = (username, password) def api_endpoint(self): return "%s/api2" % self.server - def ping(self,auth=False): + def ping(self, auth=False): try: - return self.session.get("%s%s/ping" % (self.api_endpoint(),"/auth" if auth else "")).text == "\"pong\"" + return self.session.get("%s%s/ping" % (self.api_endpoint(), "/auth" if auth else "")).text == "\"pong\"" except: return False - def obtain_token(self): - user,passw = self.login + user, passw = self.login try: - req=requests.post("%s/auth-token/" % self.api_endpoint(), data = {'username': user, 'password': passw }) + req = requests.post("%s/auth-token/" % self.api_endpoint(), + data={'username': user, 'password': passw}) json = req.json() if "non_field_errors" in json: print(json["non_field_errors"]) return False - return SeafileToken(user,json["token"]) + return SeafileToken(user, json["token"]) except: return False def authorize(self): self.token = self.obtain_token() if self.token: - self.session.headers.update({'Authorization': "Token %s" % self.token.token}) + self.session.headers.update( + {'Authorization': "Token %s" % self.token.token}) return self.token != False - #curl -H 'Authorization: Token 24fd3c026886e3121b2ca630805ed425c272cb96' -H 'Accept: application/json; indent=4' https://cloud.seafile.com/api2/repos/ + # curl -H 'Authorization: Token 24fd3c026886e3121b2ca630805ed425c272cb96' -H 'Accept: application/json; indent=4' https://cloud.seafile.com/api2/repos/ def libraries(self): - resp=self.session.get("%s/repos/" % self.api_endpoint(), headers = {'Authorization': "Token %s" % self.token.token, 'Accept': 'application/json; indent=4' }) - if not resp.status_code == 200: return - libraries=[] + resp = self.session.get("%s/repos/" % self.api_endpoint(), headers={ + 'Authorization': "Token %s" % self.token.token, 'Accept': 'application/json; indent=4'}) + if not resp.status_code == 200: + return + libraries = [] for lib in resp.json(): if not lib['encrypted']: - libraries.append(SeafileLibrary(self,lib['id'],lib['name'],lib['owner'])) + libraries.append(SeafileLibrary( + self, lib['id'], lib['name'], lib['owner'])) return libraries + class SeafileLibrary: - def __init__(self,client,id,name,owner): + def __init__(self, client, id, name, owner): self.client = client self.session = client.session self.id = id @@ -59,67 +67,73 @@ class SeafileLibrary: self.owner = owner def api_endpoint(self): - return "%s/repos/%s" % (self.client.api_endpoint(),self.id) + return "%s/repos/%s" % (self.client.api_endpoint(), self.id) - def upload(self,file,file_name,directory,link=None): + def upload(self, file, file_name, directory, link=None): def obtain_link(): - #curl -H "Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd" https://cloud.seafile.com/api2/repos/99b758e6-91ab-4265-b705-925367374cf0/upload-link/ + # curl -H "Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd" https://cloud.seafile.com/api2/repos/99b758e6-91ab-4265-b705-925367374cf0/upload-link/ print("%s/upload-link" % self.api_endpoint()) - quoted = self.session.get("%s/upload-link" % self.api_endpoint(), headers = {'Authorization': "Token %s" % self.client.token.token,}).text + quoted = self.session.get("%s/upload-link" % self.api_endpoint(), headers={ + 'Authorization': "Token %s" % self.client.token.token, }).text return quoted[1:-1] - #curl -H "Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd" -F file=@test.txt -F filename=test.txt -F parent_dir=/ http://cloud.seafile.com:8082/upload-api/73c5d117-3bcf-48a0-aa2a-3f48d5274ae3 - resp = self.session.post(link or obtain_link() , - files={'file': (file_name,open(file, 'rb')), 'parent_dir': directory, 'target_file': "%s/%s" % (directory,file_name)}, - headers = {'Authorization': "Token %s" % self.client.token.token,} - ) + # curl -H "Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd" -F file=@test.txt -F filename=test.txt -F parent_dir=/ http://cloud.seafile.com:8082/upload-api/73c5d117-3bcf-48a0-aa2a-3f48d5274ae3 + resp = self.session.post(link or obtain_link(), + files={'file': (file_name, open( + file, 'rb')), 'parent_dir': directory, 'target_file': "%s/%s" % (directory, file_name)}, + headers={ + 'Authorization': "Token %s" % self.client.token.token, } + ) if resp.status_code == 200: - return SeafileFile(self,("%s/%s" % (directory,file_name)).replace('//','/').replace('//','/'),resp.text) + return SeafileFile(self, ("%s/%s" % (directory, file_name)).replace('//', '/').replace('//', '/'), resp.text) return False - #curl -H 'Authorization: Token f2210dacd3606d94ff8e61d99b477fd' -H 'Accept: application/json; charset=utf-8; indent=4' https://cloud.seafile.com/api2/repos/dae8cecc-2359-4d33-aa42-01b7846c4b32/file/detail/?p=/foo.c - def file_info(self,path): - resp=self.session.get("%s/file/detail/?p=%s" % (self.api_endpoint(),path), headers = {'Authorization': "Token %s" % self.token.token, 'Accept': 'application/json; indent=4' }) + # curl -H 'Authorization: Token f2210dacd3606d94ff8e61d99b477fd' -H 'Accept: application/json; charset=utf-8; indent=4' https://cloud.seafile.com/api2/repos/dae8cecc-2359-4d33-aa42-01b7846c4b32/file/detail/?p=/foo.c + def file_info(self, path): + resp = self.session.get("%s/file/detail/?p=%s" % (self.api_endpoint(), path), headers={ + 'Authorization': "Token %s" % self.token.token, 'Accept': 'application/json; indent=4'}) if resp.status_code == 200: json = resp.json() - return SeafileFile(self,path,json['id'],json['size']) + return SeafileFile(self, path, json['id'], json['size']) return False def __str__(self): - return "%s on %s by %s" % (self.name,self.client.server,self.owner) + return "%s on %s by %s" % (self.name, self.client.server, self.owner) + class SeafileFile: - def __init__(self,library,path,id,size=0): + def __init__(self, library, path, id, size=0): self.id = id self.path = path self.library = library self.session = library.session self.size = size - #curl -v -X PUT -d "p=/foo.md" -H 'Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd' -H 'Accept: application/json; indent=4' https://cloud.seafile.com/api2/repos/afc3b694-7d4c-4b8a-86a4-89c9f3261b12/file/shared-link/ + # curl -v -X PUT -d "p=/foo.md" -H 'Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd' -H 'Accept: application/json; indent=4' https://cloud.seafile.com/api2/repos/afc3b694-7d4c-4b8a-86a4-89c9f3261b12/file/shared-link/ def share(self): - resp = self.session.put("%s/repos/%s/file/shared-link/" % (self.library.client.api_endpoint(),self.library.id), - headers = {'Authorization': "Token %s" % self.library.client.token.token, 'Accept': 'application/json; indent=4'}, - data = {'p': self.path} - ) + resp = self.session.put("%s/repos/%s/file/shared-link/" % (self.library.client.api_endpoint(), self.library.id), + headers={'Authorization': "Token %s" % self.library.client.token.token, + 'Accept': 'application/json; indent=4'}, + data={'p': self.path} + ) return resp.headers.get("location") - def update(self,file): + def update(self, file): def obtain_link(): - #curl -H "Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd" https://cloud.seafile.com/api2/repos/99b758e6-91ab-4265-b705-925367374cf0/upload-link/ - quoted = self.session.get("%s/update-link" % self.library.api_endpoint(), headers = {'Authorization': "Token %s" % self.library.client.token.token,}).text + # curl -H "Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd" https://cloud.seafile.com/api2/repos/99b758e6-91ab-4265-b705-925367374cf0/upload-link/ + quoted = self.session.get("%s/update-link" % self.library.api_endpoint(), headers={ + 'Authorization': "Token %s" % self.library.client.token.token, }).text return quoted[1:-1] directory, name = os.path.split(self.path) - return self.library.upload(file,name,directory,obtain_link()) + return self.library.upload(file, name, directory, obtain_link()) + class SeafileToken: - def __init__(self,username,token): + def __init__(self, username, token): self.username = username self.token = token def __str__(self): - return "%s@%s" % (self.token,self.username) - - + return "%s@%s" % (self.token, self.username) diff --git a/imports/settings.py b/imports/settings.py new file mode 100644 index 0000000..4d0f8b8 --- /dev/null +++ b/imports/settings.py @@ -0,0 +1,72 @@ +from processors import DummyProcessor, DefaultProcessor, EncryptedProcessor +from seafapi import * + + +class SeafScreencloudSettings: + + def __init__(self): + self.processor = DummyProcessor() + self.library = None # (Id, Name) + self.library_path = "/" + self.token = None # SefileToken + self.upload_scheme = "regular" + self.url = None + + def _client(self): + if self.token and self.url: + client = SeafileClient( + self.url, self.token.username, token=self.token) + + def c(): + return client + self.client = c + return c() + return None + + def load(self, settings): + + self.client = self._client + + self.url = settings.value("seafile-url", None) + lib = tuple(settings.value("library", "/").split("/")) + (id, name) = lib + if len(id) == 0 or self.client() == None: + self.library = None + else: + self.library = SeafileLibrary(self.client(), id, name, name) + self.library_path = settings.value("library-path", "/") + (user, tkn) = (settings.value("auth-username", None), + settings.value("auth-token", None)) + if user == None or tkn == None: + self.token = None + else: + self.token = SeafileToken(user, tkn) + + processors = { + "default": DefaultProcessor, + "enc": EncryptedProcessor + } + + if settings.value("processor", None) in processors: + self.processor = processors[settings.value("processor", None)]( + self.library, self.library_path) + self.processor.load_settings(settings) + elif self.library: + self.processor = DefaultProcessor(self.library, self.library_path) + else: + self.processor = DummyProcessor() + + # TODO: + self.upload_scheme = "regular" + + def save(self, settings): + settings.setValue("seafile-url", self.url) + if self.library is not None: + settings.setValue("library", "%s/%s" % + (self.library.id, self.library.name)) + settings.setValue("library-path", self.library_path) + if self.token != None: + settings.setValue("auth-username", self.token.username) + settings.setValue("auth-token", self.token.token) + settings.setValue("processor", self.processor.name()) + self.processor.save_settings(settings) diff --git a/main.py b/main.py index d64fdfe..aaeea80 100644 --- a/main.py +++ b/main.py @@ -3,9 +3,10 @@ import time from PythonQt.QtCore import QFile, QSettings from PythonQt.QtGui import QDesktopServices, QMessageBox from PythonQt.QtUiTools import QUiLoader -from multiprocessing import Pool,Process +from multiprocessing import Pool, Process from seafapi import * +from settings import SeafScreencloudSettings from processors import DummyProcessor, DefaultProcessor, EncryptedProcessor ############################### ## This is a temporary fix, should be removed when a newer python version is used ## @@ -13,27 +14,29 @@ import logging logging.captureWarnings(True) ############################### + class SeafileUploader(): def __init__(self): - self.processor = DummyProcessor() - self.seaf_lib = None - self.seaf_path = "/" + self.set = SeafScreencloudSettings() self.libs = None self.uil = QUiLoader() self.loadSettings() self.pool = Pool(2) - self.seaf_client = None - + def showSettingsUI(self, parentWidget): self.parentWidget = parentWidget - #self.processor.configure(parentWidget) - self.settingsDialog = self.uil.load(QFile(workingDir + "/settings.ui"), parentWidget) - self.settingsDialog.group_account.widget_loggedIn.loginButton.connect("clicked()", self.startAuthenticationProcess) + # self.set.processor.configure(parentWidget) + self.settingsDialog = self.uil.load( + QFile(workingDir + "/settings.ui"), parentWidget) + self.settingsDialog.group_account.widget_loggedIn.loginButton.connect( + "clicked()", self.startAuthenticationProcess) #self.settingsDialog.group_name.input_name.connect("textChanged(QString)", self.nameFormatEdited) - self.settingsDialog.group_location.widget_location.pathEdit.connect("textChanged(QString)", self.locationUpdate) - self.settingsDialog.group_location.widget_location.libraryEditDrop.connect("currentIndexChanged(QString)", self.locationUpdate) + self.settingsDialog.group_location.widget_location.pathEdit.connect( + "textChanged(QString)", self.locationUpdate) + self.settingsDialog.group_location.widget_location.libraryEditDrop.connect( + "currentIndexChanged(QString)", self.locationUpdate) self.settingsDialog.connect("accepted()", self.saveSettings) - + self.loadSettings() self.updateUi() self.settingsDialog.open() @@ -43,29 +46,35 @@ class SeafileUploader(): drop.clear() drop.setEnabled(False) select = 0 - if self.seaf_client and self.seaf_client.ping(): - self.libs = (self.seaf_client or self.seaf_lib.client).libraries() - i=0 + if self.set.client() and self.set.client().ping(): + self.libs = self.set.client().libraries() + i = 0 for lib in self.libs: - if self.seaf_lib is not None and lib.id == self.seaf_lib.id: + if self.set.library is not None and (lib.id == self.set.library.id or lib.name == self.set.library.name): select = i print("set %s" % lib.name) drop.addItem(lib.name) - i=i+1 + i = i+1 drop.setCurrentIndex(select) drop.setEnabled(True) def updateUi(self): - self.settingsDialog.group_account.widget_loggedIn.usernameEdit.setText(self.access_token.username if not (self.access_token is None) else "") - self.settingsDialog.group_account.widget_loggedIn.serverUrlEdit.setText(self.seaf_url or "https://seaf.shimun.net") - self.settingsDialog.group_account.widget_loggedIn.loginButton.setText("Logout" if self.access_token is not None else "Login") + self.settingsDialog.group_account.widget_loggedIn.usernameEdit.setText( + self.set.token.username if not (self.set.token is None) else "") + self.settingsDialog.group_account.widget_loggedIn.serverUrlEdit.setText( + self.set.url or "https://seaf.shimun.net") + self.settingsDialog.group_account.widget_loggedIn.loginButton.setText( + "Logout" if self.set.token is not None else "Login") # - if self.access_token is None and len(self.settingsDialog.group_account.widget_loggedIn.passwordEdit.text) > 0: - self.settingsDialog.group_account.widget_loggedIn.passwordEdit.setText("X" * 8) + if self.set.token is None and len(self.settingsDialog.group_account.widget_loggedIn.passwordEdit.text) > 0: + self.settingsDialog.group_account.widget_loggedIn.passwordEdit.setText( + "X" * 8) for elm in [self.settingsDialog.group_account.widget_loggedIn.usernameEdit, self.settingsDialog.group_account.widget_loggedIn.serverUrlEdit, self.settingsDialog.group_account.widget_loggedIn.passwordEdit]: - elm.setEnabled(self.access_token is None) - self.settingsDialog.group_location.setEnabled(self.access_token is not None) - self.settingsDialog.group_location.widget_location.pathEdit.setText(self.lib_path or "/") + elm.setEnabled(self.set.token is None) + self.settingsDialog.group_location.setEnabled( + self.set.token is not None) + self.settingsDialog.group_location.widget_location.pathEdit.setText( + self.set.library_path or "/") self.settingsDialog.linkCopyCheck.setChecked(self.copyLink) self.populateLibrarySelector() self.settingsDialog.adjustSize() @@ -74,106 +83,86 @@ class SeafileUploader(): settings = QSettings() settings.beginGroup("uploaders") settings.beginGroup("seafile") - self.seaf_url = settings.value("seafile-url", "") - (self.lib_id,self.lib_name) = str(settings.value("library", "/")).split("/") - self.lib_path = settings.value("library-path", "") + self.set.load(settings) self.copyLink = settings.value("copy-link", "true") in ['true', True] - if settings.value("auth-token", False) and settings.value("auth-username", False): - self.access_token = SeafileToken(settings.value("auth-username", False),settings.value("auth-token", False)) - else: - self.access_token = None - self.nameFormat = settings.value("name-format", "Screenshot %Y-%m-%d %H_%M_%S") + self.nameFormat = settings.value( + "name-format", "Screenshot %Y-%m-%d %H_%M_%S") self.upload_scheme = settings.value("upload-scheme", "regular") settings.endGroup() settings.endGroup() - if self.seaf_url and self.access_token: - self.seaf_client = SeafileClient(self.seaf_url,self.access_token.username,token=self.access_token) - if self.seaf_client.ping(): - for lib in self.seaf_client.libraries(): - if lib.id == self.lib_id: - self.seaf_lib = lib - if self.seaf_lib and self.seaf_path: - self.processor = EncryptedProcessor(self.seaf_lib,self.lib_path)#DefaultProcessor(self.seaf_lib,self.lib_path) - def saveSettings(self): settings = QSettings() settings.beginGroup("uploaders") settings.beginGroup("seafile") + self.set.save(settings) try: self.copyLink = self.settingsDialog.linkCopyCheck.checked except: pass settings.setValue("copy-link", self.copyLink) - if self.access_token is not None: - settings.setValue("auth-username", self.access_token.username ) - settings.setValue("auth-token", self.access_token.token) - settings.setValue("seafile-url", self.seaf_url) - if self.seaf_lib is not None: - settings.setValue("library", "%s/%s" % (self.seaf_lib.id,self.seaf_lib.name)) - settings.setValue("library-path", self.lib_path) settings.setValue("name-format", self.nameFormat) - settings.setValue("upload-scheme", self.upload_scheme) - #settings.setValue("name-format", self.settingsDialog.group_name.input_name.text) - print(self.seaf_lib, self.lib_path) settings.endGroup() settings.endGroup() - + def isConfigured(self): - return self.access_token and self.seaf_url and self.processor.is_configured() + return self.set.library and self.set.processor.is_configured() def getFilename(self): self.loadSettings() return ScreenCloud.formatFilename(self.nameFormat) - + def upload(self, screenshot, name): self.loadSettings() - #Make sure we have a up to date token - if not self.seaf_lib: + # Make sure we have a up to date token + if not self.set.library: ScreenCloud.setError("Not configured properly") return False - #Save to a temporary file + # Save to a temporary file timestamp = time.time() + def tempfile(name): try: return QDesktopServices.storageLocation(QDesktopServices.TempLocation) + "/" + name except AttributeError: - from PythonQt.QtCore import QStandardPaths #fix for Qt5 + from PythonQt.QtCore import QStandardPaths # fix for Qt5 return QStandardPaths.writableLocation(QStandardPaths.TempLocation) + "/" + name tmpFilename = tempfile(ScreenCloud.formatFilename(str(timestamp))) screenshot.save(QFile(tmpFilename), ScreenCloud.getScreenshotFormat()) - #Upload! - link=None - if True: - #try: - link = self.processor.upload(tmpFilename,self.getFilename()) + # Upload! + link = None + # if True: + try: + link = self.set.processor.upload(tmpFilename, self.getFilename()) if self.copyLink: ScreenCloud.setUrl(link) - #except Exception as e: - # ScreenCloud.setError("Failed to upload to seafile. " + e.message) - # return False + except Exception as e: + ScreenCloud.setError("Failed to upload to seafile. Using: %s\n\n%s" % ( + self.set.processor.name(), e.message)) + return False return True def startAuthenticationProcess(self): self.saveSettings() self.loadSettings() - if self.access_token is not None: + if self.set.token is not None: self.logOut() return if self.settingsDialog.group_account.widget_loggedIn.serverUrlEdit.text \ and self.settingsDialog.group_account.widget_loggedIn.usernameEdit.text \ and self.settingsDialog.group_account.widget_loggedIn.passwordEdit.text: - self.seaf_url = self.settingsDialog.group_account.widget_loggedIn.serverUrlEdit.text + self.set.url = self.settingsDialog.group_account.widget_loggedIn.serverUrlEdit.text if True: - #try: - self.login(self.settingsDialog.group_account.widget_loggedIn.usernameEdit.text,self.settingsDialog.group_account.widget_loggedIn.passwordEdit.text) + # try: + self.login(self.settingsDialog.group_account.widget_loggedIn.usernameEdit.text, + self.settingsDialog.group_account.widget_loggedIn.passwordEdit.text) self.saveSettings() self.loadSettings() self.populateLibrarySelector() - #except Exception as e: + # except Exception as e: #QMessageBox.critical(self.settingsDialog, "Failed to login", "Verify your server url and credentials" + e.message) self.saveSettings() self.updateUi() @@ -181,31 +170,32 @@ class SeafileUploader(): def locationUpdate(self): drop = self.settingsDialog.group_location.widget_location.libraryEditDrop selected_lib = drop.currentText - if not drop.isEnabled(): return #not populated - self.lib_path = self.settingsDialog.group_location.widget_location.pathEdit.text - print(self.lib_path, selected_lib) - if self.libs is None: return + if not drop.isEnabled(): + return # not populated + self.set.library_path = self.settingsDialog.group_location.widget_location.pathEdit.text + print(self.set.library_path, selected_lib) + if self.libs is None: + return for lib in self.libs: if lib.name == selected_lib: - self.seaf_lib = lib + self.set.library = lib print("%s user selected" % selected_lib) - - def login(self,user,password): - cli = SeafileClient(self.seaf_url,user,password) - self.access_token = cli.obtain_token() + def login(self, user, password): + cli = SeafileClient(self.set.url, user, password) + self.set.token = cli.obtain_token() def logOut(self): settings = QSettings() settings.beginGroup("uploaders") settings.beginGroup("seafile") settings.remove("auth-token") - self.access_token = None + self.set.token = None settings.endGroup() settings.endGroup() self.loadSettings() self.updateUi() def nameFormatEdited(self, nameFormat): - self.settingsDialog.group_name.label_example.setText(ScreenCloud.formatFilename(nameFormat, False)) - + self.settingsDialog.group_name.label_example.setText( + ScreenCloud.formatFilename(nameFormat, False)) diff --git a/make-modules.sh b/make-modules.sh index 07eb8cd..660789f 100755 --- a/make-modules.sh +++ b/make-modules.sh @@ -1,5 +1,4 @@ -rm -rf modules -mkdir modules -pip3 install --install-option="--prefix=$PWD" -r requirements.txt -mv lib/python3.5/site-packages/* modules/ +mkdir -p modules +pip3 install --install-option="--prefix=$PWD" -r requirements.txt "$@" +mv lib/python3.*/site-packages/* modules/ cp imports/* -r modules/