reborked the token system

This commit is contained in:
Ville Rantanen
2018-03-01 15:05:29 +02:00
parent 9ed8c18fb3
commit 06d42ee956
4 changed files with 241 additions and 152 deletions

View File

@@ -19,20 +19,20 @@ def get_root_path(opts):
def list_shares(shares,opts):
table = []
table.append(('Name', 'Path','Public','Password','PassHash','Upload','Overwrite','Direct','Expire','Recipient','Description'))
table.append(('Name', 'Path','Public','Password','Tokens','Upload','Overwrite','Direct','Expire','Recipient','Description'))
for share in shares:
public = get_or_none('public',share, False)
passhash = '-'
passtoken = '-'
password = 'pass_hash' in share
if opts.show_password:
if 'pass_plain' in share:
password = share['pass_plain']
else:
password = ""
if 'pass_hash' in share:
passhash = share['pass_hash']
if 'tokens' in share:
passtoken = ",".join(share['tokens'])
else:
passhash = "-"
passtoken = ""
upload = get_or_none('upload',share, False)
overwrite = get_or_none('overwrite',share, True)
direct = get_or_none('direct_links',share, False) if password else False
@@ -43,7 +43,7 @@ def list_shares(shares,opts):
share['path']+"/",
public,
password,
passhash,
passtoken,
upload,
overwrite,
direct,
@@ -102,6 +102,7 @@ def add_share(shares, config, opts):
if opts.plain:
share['pass_plain'] = opts.password
share['pass_hash'] = password_hash(opts.password, config['app_secret_key'])
share['tokens'] = [random_token()]
if opts.expire:
try:
date_object = datetime.strptime(opts.expire,"%Y-%m-%d %H:%M")
@@ -138,7 +139,9 @@ def modify_share(shares, config, opts):
for i,share in enumerate(shares):
if share['name'] != opts.name:
continue
orig_share = share.copy()
orig_share = dict(share)
if 'tokens' in share:
orig_share['tokens'] = list(share['tokens'])
print(json.dumps(share, indent = 2, sort_keys = True))
found = True
break
@@ -167,6 +170,19 @@ def modify_share(shares, config, opts):
share['pass_plain'] = opts.password
share['pass_hash'] = password_hash(opts.password, config['app_secret_key'])
# Handle tokens
if opts.remove_tokens:
for token in opts.remove_tokens:
if token in share['tokens']:
share['tokens'].remove(token)
if opts.tokens:
for token in opts.tokens:
if not 'tokens' in share:
share['tokens'] = []
if not token in share['tokens']:
share['tokens'].append(token)
if opts.expire:
if opts.expire == "":
# REMOVE EXPIRATION
@@ -201,7 +217,7 @@ def modify_share(shares, config, opts):
if not key in orig_share:
modified.append(key)
continue
if orig_share[key] != share[key]:
if str(orig_share[key]) != str(share[key]):
modified.append(key)
continue
for key in orig_share:
@@ -242,109 +258,161 @@ def print_rest_api(shares, config, opts):
share = shares[0]
if opts.type == "list":
print("Link to enter the share:")
print("%s/list/%s"%(
config['public_url'],
share['name']
))
print_rest_api_list(config,share)
return
if not 'pass_hash' in share:
print("REST API enabled only if pass_hash is set for share")
sys.exit(1)
crypter = Crypto(config['app_secret_key'])
crypted = crypter.encrypt(share['pass_hash'])
if opts.type == "login":
print("Link to automatically login in the share:")
print("%s/list/%s/%s"%(
config['public_url'],
share['name'],
crypted
))
elif opts.type == "upload":
if 'upload' not in share or not share['upload']:
print("Uploading not allowed to this share")
sys.exit(0)
print("Link to upload file to the share:")
print("\n# curl -F file=@'the_file_name.ext' %s/upload/%s/%s"%(
config['public_url'],
share['name'],
crypted
))
print("\nLink to upload multiple files to the share:")
print("\n# curl -s %s/script/upload/%s/%s | bash /dev/stdin file_to_upload.ext [second.file.ext]"%(
config['public_url'],
share['name'],
crypted
))
print("\nLink to upload multiple files to the share, splitting large files (default 512Mb):")
print("\n# curl -s %s/script/upload_split/%s/%s | bash /dev/stdin [-s split_size_in_Mb] file_to_upload.ext [second.file.ext]"%(
config['public_url'],
share['name'],
crypted
))
if (not 'tokens' in share) or len(share['tokens']) == 0:
print("REST API enabled only if tokens are set for the share")
sys.exit(1)
token = False
if len(share['tokens']) == 1:
token = share['tokens'][0]
else:
try:
token_int = int(opts.token) - 1
if token_int < 0:
raise ValueError
token = share['tokens'][token_int]
except (IndexError, ValueError, TypeError) as e:
if opts.token in share['tokens']:
token = opts.token
if not token:
# more tokens!
if opts.token:
print("No such token for this share")
print("Tokens:")
for i,token in enumerate(share['tokens']):
print("%d. %s"%( i+1, token ))
print("Run again with --token [nr]")
if not opts.token:
sys.exit(0)
else:
sys.exit(1)
if opts.type == "login":
print_rest_api_login(config,share,token)
elif opts.type == "upload":
print_rest_api_upload(config,share,token)
elif opts.type == "download":
print("Links to download files:")
share_path = os.path.join(
config['__root_path__'],
config['data_folder'],
share['path']
)
if not os.path.exists(share_path):
print("no files")
sys.exit(0)
for filename in sorted(os.listdir(share_path)):
if os.path.isdir(os.path.join(share_path,filename)):
continue
if filename.startswith("."):
continue
print("%s/download/%s/%s/%s"%(
config['public_url'],
share['name'],
crypted,
filename
))
print("or \n\n# curl -s %s/script/download/%s/%s | bash /dev/stdin [-f]"%(
config['public_url'],
share['name'],
crypted
))
print_rest_api_download(config, share, token)
elif opts.type == "direct":
if 'direct_links' not in share or not share['direct_links']:
print("Direct downloading not allowed in this share")
sys.exit(0)
print("Links to direct download files:")
share_path = os.path.join(
config['__root_path__'],
config['data_folder'],
share['path']
)
if not os.path.exists(share_path):
print("no files")
sys.exit(0)
for filename in sorted(os.listdir(share_path)):
if os.path.isdir(os.path.join(share_path,filename)):
continue
if filename.startswith("."):
continue
print("%s/direct/%s/%s/%s"%(
config['public_url'],
share['name'],
get_direct_token(share,filename),
filename
))
print("or \n\n# curl -s %s/script/direct/%s/%s | bash /dev/stdin [-f]"%(
config['public_url'],
share['name'],
crypted
))
print_rest_api_direct(config, share, token)
elif opts.type == "zip":
print("ZIP download:")
print("%s/zip/%s/%s"%(
print_rest_api_zip(config, share, token)
def print_rest_api_list(config, share):
print("Link to enter the share:")
print("%s/list/%s"%(
config['public_url'],
share['name']
))
def print_rest_api_login(config, share, token):
print("Link to automatically login in the share:")
print("%s/list/%s/%s"%(
config['public_url'],
share['name'],
token
))
def print_rest_api_upload(config, share, token):
if 'upload' not in share or not share['upload']:
print("Uploading not allowed to this share")
sys.exit(0)
print("Link to upload file to the share:")
print("\n# curl -F file=@'the_file_name.ext' %s/upload/%s/%s"%(
config['public_url'],
share['name'],
token
))
print("\nLink to upload multiple files to the share:")
print("\n# curl -s %s/script/upload/%s/%s | bash /dev/stdin file_to_upload.ext [second.file.ext]"%(
config['public_url'],
share['name'],
token
))
print("\nLink to upload multiple files to the share, splitting large files (default 512Mb):")
print("\n# curl -s %s/script/upload_split/%s/%s | bash /dev/stdin [-s split_size_in_Mb] file_to_upload.ext [second.file.ext]"%(
config['public_url'],
share['name'],
token
))
def print_rest_api_download(config, share, token):
print("Links to download files:")
share_path = os.path.join(
config['__root_path__'],
config['data_folder'],
share['path']
)
if not os.path.exists(share_path):
print("no files")
sys.exit(0)
for filename in sorted(os.listdir(share_path)):
if os.path.isdir(os.path.join(share_path,filename)):
continue
if filename.startswith("."):
continue
print("%s/download/%s/%s/%s"%(
config['public_url'],
share['name'],
crypted
token,
filename
))
print("or \n\n# curl -s %s/script/download/%s/%s | bash /dev/stdin [-f]"%(
config['public_url'],
share['name'],
token
))
def print_rest_api_direct(config, share, token):
if 'direct_links' not in share or not share['direct_links']:
print("Direct downloading not allowed in this share")
sys.exit(0)
print("Links to direct download files:")
share_path = os.path.join(
config['__root_path__'],
config['data_folder'],
share['path']
)
if not os.path.exists(share_path):
print("no files")
sys.exit(0)
for filename in sorted(os.listdir(share_path)):
if os.path.isdir(os.path.join(share_path,filename)):
continue
if filename.startswith("."):
continue
print("%s/direct/%s/%s/%s"%(
config['public_url'],
share['name'],
get_direct_token(share,filename),
filename
))
print("or \n\n# curl -s %s/script/direct/%s/%s | bash /dev/stdin [-f]"%(
config['public_url'],
share['name'],
token
))
def print_rest_api_zip(config, share, token):
print("ZIP download:")
print("%s/zip/%s/%s"%(
config['public_url'],
share['name'],
token
))
def print_token():
print(random_token())
def parse_options():
@@ -431,6 +499,12 @@ def parse_options():
parser_modify.add_argument('-r','--recipient', action="store", dest="recipient", default = None,
help= "Recipient for notifications (if enabled)"
)
parser_modify.add_argument('-t','--add-token', action="append", dest="tokens", default = [],
help= "Token for REST api, may be issued multiple times"
)
parser_modify.add_argument('--remove-token', action="append", dest="remove_tokens", default = [],
help= "Remove REST tokens, may be issued multiple times"
)
parser_modify.add_argument('-w','--write', action="store_true", dest="write", default = False,
help = "Write changes to the shares.json file"
)
@@ -440,6 +514,11 @@ def parse_options():
parser_rest.add_argument(dest="type", help = "Type of command",
choices = ['list','login','upload','download','direct','zip']
)
parser_rest.add_argument('-t','--token', action="store", dest="token", default = None,
help= "If share has multiple tokens, select one to print REST API for."
)
## TOKEN
parser_token = subparsers.add_parser('token', help = "Generate a random token")
return parser.parse_args()
@@ -477,6 +556,8 @@ if __name__ == "__main__":
modify_share(shares,config,opts)
elif opts.subparser_name == 'rest':
print_rest_api(shares,config,opts)
elif opts.subparser_name == 'token':
print_token()