2019-08-05 09:11:29 +00:00
#!/usr/bin/env python
2019-11-15 11:15:07 +00:00
import argparse
2020-01-31 18:04:00 +00:00
import base64
2019-12-25 17:20:19 +00:00
from datetime import datetime
2019-11-15 11:15:07 +00:00
import json
2019-12-27 22:12:44 +00:00
import platform
2019-12-29 16:21:25 +00:00
import sys
import time
2019-12-25 17:20:19 +00:00
2019-08-01 22:00:48 +00:00
import requests
2019-08-05 09:11:29 +00:00
try :
import urllib . parse as urlparse
except ImportError :
import urlparse
2019-08-01 22:00:48 +00:00
2019-08-08 12:20:42 +00:00
try :
import pygments
from pygments . lexers import JsonLexer
from pygments . formatters import TerminalFormatter
except ImportError :
pygments = None
2019-12-29 16:21:25 +00:00
try :
import pwd
import spwd
except ImportError :
pwd = None
2019-08-01 22:00:48 +00:00
class SFTPGoApiRequests :
2019-08-08 12:20:42 +00:00
def __init__ ( self , debug , baseUrl , authType , authUser , authPassword , secure , no_color ) :
2019-08-08 10:03:24 +00:00
self . userPath = urlparse . urljoin ( baseUrl , ' /api/v1/user ' )
2020-06-07 21:30:18 +00:00
self . folderPath = urlparse . urljoin ( baseUrl , ' /api/v1/folder ' )
2019-08-08 10:03:24 +00:00
self . quotaScanPath = urlparse . urljoin ( baseUrl , ' /api/v1/quota_scan ' )
2020-06-07 21:30:18 +00:00
self . folderQuotaScanPath = urlparse . urljoin ( baseUrl , ' /api/v1/folder_quota_scan ' )
2019-08-24 12:41:15 +00:00
self . activeConnectionsPath = urlparse . urljoin ( baseUrl , ' /api/v1/connection ' )
2019-08-08 10:03:24 +00:00
self . versionPath = urlparse . urljoin ( baseUrl , ' /api/v1/version ' )
2019-11-14 17:48:01 +00:00
self . providerStatusPath = urlparse . urljoin ( baseUrl , ' /api/v1/providerstatus ' )
2019-12-27 22:12:44 +00:00
self . dumpDataPath = urlparse . urljoin ( baseUrl , ' /api/v1/dumpdata ' )
self . loadDataPath = urlparse . urljoin ( baseUrl , ' /api/v1/loaddata ' )
2020-06-20 10:38:04 +00:00
self . updateUsedQuotaPath = urlparse . urljoin ( baseUrl , " /api/v1/quota_update " )
self . updateFolderUsedQuotaPath = urlparse . urljoin ( baseUrl , " /api/v1/folder_quota_update " )
2019-08-01 22:00:48 +00:00
self . debug = debug
2019-08-08 10:03:24 +00:00
if authType == ' basic ' :
2019-08-07 21:06:26 +00:00
self . auth = requests . auth . HTTPBasicAuth ( authUser , authPassword )
2019-08-08 10:03:24 +00:00
elif authType == ' digest ' :
2019-08-07 21:06:26 +00:00
self . auth = requests . auth . HTTPDigestAuth ( authUser , authPassword )
2019-08-07 06:59:46 +00:00
else :
self . auth = None
2019-08-08 10:03:24 +00:00
self . verify = secure
2019-08-08 12:20:42 +00:00
self . no_color = no_color
2019-08-01 22:00:48 +00:00
def formatAsJSON ( self , text ) :
if not text :
2020-01-31 18:10:45 +00:00
return ' '
2019-08-08 12:20:42 +00:00
json_string = json . dumps ( json . loads ( text ) , sort_keys = True , indent = 2 )
if not self . no_color and pygments :
return pygments . highlight ( json_string , JsonLexer ( ) , TerminalFormatter ( ) )
return json_string
2019-08-01 22:00:48 +00:00
def printResponse ( self , r ) :
2020-01-31 18:10:45 +00:00
if ' content-type ' in r . headers and ' application/json ' in r . headers [ ' content-type ' ] :
2019-08-01 22:00:48 +00:00
if self . debug :
2019-08-08 12:20:42 +00:00
if pygments is None :
print ( ' ' )
print ( ' Response color highlight is not available: you need pygments 1.5 or above. ' )
print ( ' ' )
2020-01-31 18:10:45 +00:00
print ( ' Executed request: {} {} - request body: {} ' . format (
2019-08-08 12:20:42 +00:00
r . request . method , r . url , self . formatAsJSON ( r . request . body ) ) )
print ( ' ' )
2020-01-31 18:10:45 +00:00
print ( ' Got response, status code: {} body: ' . format ( r . status_code ) )
2019-08-01 22:00:48 +00:00
print ( self . formatAsJSON ( r . text ) )
else :
print ( r . text )
2020-01-31 18:10:45 +00:00
def buildUserObject ( self , user_id = 0 , username = ' ' , password = ' ' , public_keys = [ ] , home_dir = ' ' , uid = 0 , gid = 0 ,
2020-01-19 06:41:05 +00:00
max_sessions = 0 , quota_size = 0 , quota_files = 0 , permissions = { } , upload_bandwidth = 0 , download_bandwidth = 0 ,
status = 1 , expiration_date = 0 , allowed_ip = [ ] , denied_ip = [ ] , fs_provider = ' local ' , s3_bucket = ' ' ,
2020-01-19 22:23:09 +00:00
s3_region = ' ' , s3_access_key = ' ' , s3_access_secret = ' ' , s3_endpoint = ' ' , s3_storage_class = ' ' ,
2020-02-19 08:41:15 +00:00
s3_key_prefix = ' ' , gcs_bucket = ' ' , gcs_key_prefix = ' ' , gcs_storage_class = ' ' , gcs_credentials_file = ' ' ,
2020-03-01 21:10:29 +00:00
gcs_automatic_credentials = ' automatic ' , denied_login_methods = [ ] , virtual_folders = [ ] ,
2020-03-13 18:13:58 +00:00
denied_extensions = [ ] , allowed_extensions = [ ] , s3_upload_part_size = 0 , s3_upload_concurrency = 0 ) :
2020-01-31 18:10:45 +00:00
user = { ' id ' : user_id , ' username ' : username , ' uid ' : uid , ' gid ' : gid ,
' max_sessions ' : max_sessions , ' quota_size ' : quota_size , ' quota_files ' : quota_files ,
' upload_bandwidth ' : upload_bandwidth , ' download_bandwidth ' : download_bandwidth ,
' status ' : status , ' expiration_date ' : expiration_date }
2019-12-29 13:07:44 +00:00
if password is not None :
2020-01-31 18:10:45 +00:00
user . update ( { ' password ' : password } )
2019-08-07 21:41:10 +00:00
if public_keys :
2019-12-29 13:07:44 +00:00
if len ( public_keys ) == 1 and not public_keys [ 0 ] :
2020-01-31 18:10:45 +00:00
user . update ( { ' public_keys ' : [ ] } )
2019-12-29 13:07:44 +00:00
else :
2020-01-31 18:10:45 +00:00
user . update ( { ' public_keys ' : public_keys } )
2019-08-17 13:20:49 +00:00
if home_dir :
2020-01-31 18:10:45 +00:00
user . update ( { ' home_dir ' : home_dir } )
2019-08-17 13:20:49 +00:00
if permissions :
2020-01-31 18:10:45 +00:00
user . update ( { ' permissions ' : permissions } )
2020-02-23 10:30:26 +00:00
if virtual_folders :
user . update ( { ' virtual_folders ' : self . buildVirtualFolders ( virtual_folders ) } )
2020-03-01 21:10:29 +00:00
if allowed_ip or denied_ip or denied_login_methods or allowed_extensions or denied_extensions :
user . update ( { ' filters ' : self . buildFilters ( allowed_ip , denied_ip , denied_login_methods , denied_extensions ,
allowed_extensions ) } )
2020-01-31 18:10:45 +00:00
user . update ( { ' filesystem ' : self . buildFsConfig ( fs_provider , s3_bucket , s3_region , s3_access_key , s3_access_secret ,
2020-01-31 18:04:00 +00:00
s3_endpoint , s3_storage_class , s3_key_prefix , gcs_bucket ,
2020-02-19 08:41:15 +00:00
gcs_key_prefix , gcs_storage_class , gcs_credentials_file ,
2020-03-13 18:13:58 +00:00
gcs_automatic_credentials , s3_upload_part_size , s3_upload_concurrency ) } )
2019-08-01 22:00:48 +00:00
return user
2020-02-23 10:30:26 +00:00
def buildVirtualFolders ( self , vfolders ) :
result = [ ]
for f in vfolders :
if ' :: ' in f :
vpath = ' '
mapped_path = ' '
2020-06-07 21:30:18 +00:00
quota_files = 0
quota_size = 0
2020-02-23 10:30:26 +00:00
values = f . split ( ' :: ' )
if len ( values ) > 1 :
vpath = values [ 0 ]
mapped_path = values [ 1 ]
2020-05-01 13:27:53 +00:00
if len ( values ) > 2 :
try :
2020-06-07 21:30:18 +00:00
quota_files = int ( values [ 2 ] )
except :
pass
if len ( values ) > 3 :
try :
quota_size = int ( values [ 3 ] )
2020-05-01 13:27:53 +00:00
except :
pass
2020-02-23 10:30:26 +00:00
if vpath and mapped_path :
2020-05-01 13:27:53 +00:00
result . append ( { " virtual_path " : vpath , " mapped_path " : mapped_path ,
2020-06-07 21:30:18 +00:00
" quota_files " : quota_files , " quota_size " : quota_size } )
2020-02-23 10:30:26 +00:00
return result
2019-12-29 16:21:25 +00:00
def buildPermissions ( self , root_perms , subdirs_perms ) :
2019-12-25 17:20:19 +00:00
permissions = { }
if root_perms :
2020-01-31 18:10:45 +00:00
permissions . update ( { ' / ' : root_perms } )
2019-12-25 17:20:19 +00:00
for p in subdirs_perms :
2020-02-23 10:30:26 +00:00
if ' :: ' in p :
2019-12-25 17:20:19 +00:00
directory = None
values = [ ]
2020-02-23 10:30:26 +00:00
for value in p . split ( ' :: ' ) :
2019-12-25 17:20:19 +00:00
if directory is None :
directory = value
else :
2020-01-31 18:10:45 +00:00
values = [ v . strip ( ) for v in value . split ( ' , ' ) if v . strip ( ) ]
2020-02-10 18:28:35 +00:00
if directory :
2019-12-25 17:20:19 +00:00
permissions . update ( { directory : values } )
return permissions
2020-03-01 21:10:29 +00:00
def buildFilters ( self , allowed_ip , denied_ip , denied_login_methods , denied_extensions , allowed_extensions ) :
2019-12-30 17:37:50 +00:00
filters = { }
if allowed_ip :
if len ( allowed_ip ) == 1 and not allowed_ip [ 0 ] :
2020-01-19 06:41:05 +00:00
filters . update ( { ' allowed_ip ' : [ ] } )
2019-12-30 17:37:50 +00:00
else :
2020-01-19 06:41:05 +00:00
filters . update ( { ' allowed_ip ' : allowed_ip } )
2019-12-30 17:37:50 +00:00
if denied_ip :
if len ( denied_ip ) == 1 and not denied_ip [ 0 ] :
2020-01-19 06:41:05 +00:00
filters . update ( { ' denied_ip ' : [ ] } )
2019-12-30 17:37:50 +00:00
else :
2020-01-19 06:41:05 +00:00
filters . update ( { ' denied_ip ' : denied_ip } )
2020-02-19 21:39:30 +00:00
if denied_login_methods :
if len ( denied_login_methods ) == 1 and not denied_login_methods [ 0 ] :
filters . update ( { ' denied_login_methods ' : [ ] } )
else :
filters . update ( { ' denied_login_methods ' : denied_login_methods } )
2020-03-01 21:10:29 +00:00
extensions_filter = [ ]
extensions_denied = [ ]
extensions_allowed = [ ]
if denied_extensions :
for e in denied_extensions :
if ' :: ' in e :
directory = None
values = [ ]
for value in e . split ( ' :: ' ) :
if directory is None :
directory = value
else :
values = [ v . strip ( ) for v in value . split ( ' , ' ) if v . strip ( ) ]
if directory :
extensions_denied . append ( { ' path ' : directory , ' denied_extensions ' : values ,
' allowed_extensions ' : [ ] } )
if allowed_extensions :
for e in allowed_extensions :
if ' :: ' in e :
directory = None
values = [ ]
for value in e . split ( ' :: ' ) :
if directory is None :
directory = value
else :
values = [ v . strip ( ) for v in value . split ( ' , ' ) if v . strip ( ) ]
if directory :
extensions_allowed . append ( { ' path ' : directory , ' allowed_extensions ' : values ,
' denied_extensions ' : [ ] } )
if extensions_allowed and extensions_denied :
for allowed in extensions_allowed :
for denied in extensions_denied :
if allowed . get ( ' path ' ) == denied . get ( ' path ' ) :
allowed . update ( { ' denied_extensions ' : denied . get ( ' denied_extensions ' ) } )
extensions_filter . append ( allowed )
for denied in extensions_denied :
found = False
for allowed in extensions_allowed :
if allowed . get ( ' path ' ) == denied . get ( ' path ' ) :
found = True
if not found :
extensions_filter . append ( denied )
elif extensions_allowed :
extensions_filter = extensions_allowed
elif extensions_denied :
extensions_filter = extensions_denied
if allowed_extensions or denied_extensions :
filters . update ( { ' file_extensions ' : extensions_filter } )
2019-12-30 17:37:50 +00:00
return filters
2020-01-19 06:41:05 +00:00
def buildFsConfig ( self , fs_provider , s3_bucket , s3_region , s3_access_key , s3_access_secret , s3_endpoint ,
2020-02-19 08:41:15 +00:00
s3_storage_class , s3_key_prefix , gcs_bucket , gcs_key_prefix , gcs_storage_class ,
2020-03-13 18:13:58 +00:00
gcs_credentials_file , gcs_automatic_credentials , s3_upload_part_size , s3_upload_concurrency ) :
2020-01-19 06:41:05 +00:00
fs_config = { ' provider ' : 0 }
if fs_provider == ' S3 ' :
s3config = { ' bucket ' : s3_bucket , ' region ' : s3_region , ' access_key ' : s3_access_key , ' access_secret ' :
2020-01-19 22:23:09 +00:00
s3_access_secret , ' endpoint ' : s3_endpoint , ' storage_class ' : s3_storage_class , ' key_prefix ' :
2020-03-13 18:13:58 +00:00
s3_key_prefix , ' upload_part_size ' : s3_upload_part_size , ' upload_concurrency ' : s3_upload_concurrency }
2020-01-19 06:41:05 +00:00
fs_config . update ( { ' provider ' : 1 , ' s3config ' : s3config } )
2020-01-31 18:04:00 +00:00
elif fs_provider == ' GCS ' :
gcsconfig = { ' bucket ' : gcs_bucket , ' key_prefix ' : gcs_key_prefix , ' storage_class ' : gcs_storage_class }
2020-02-19 08:41:15 +00:00
if gcs_automatic_credentials == " automatic " :
gcsconfig . update ( { ' automatic_credentials ' : 1 } )
else :
gcsconfig . update ( { ' automatic_credentials ' : 0 } )
2020-01-31 18:04:00 +00:00
if gcs_credentials_file :
with open ( gcs_credentials_file ) as creds :
2020-02-19 08:41:15 +00:00
gcsconfig . update ( { ' credentials ' : base64 . b64encode ( creds . read ( ) . encode ( ' UTF-8 ' ) ) . decode ( ' UTF-8 ' ) ,
' automatic_credentials ' : 0 } )
2020-01-31 18:04:00 +00:00
fs_config . update ( { ' provider ' : 2 , ' gcsconfig ' : gcsconfig } )
2020-01-19 06:41:05 +00:00
return fs_config
2020-01-31 18:10:45 +00:00
def getUsers ( self , limit = 100 , offset = 0 , order = ' ASC ' , username = ' ' ) :
r = requests . get ( self . userPath , params = { ' limit ' : limit , ' offset ' : offset , ' order ' : order ,
' username ' : username } , auth = self . auth , verify = self . verify )
2019-08-01 22:00:48 +00:00
self . printResponse ( r )
def getUserByID ( self , user_id ) :
2020-01-31 18:10:45 +00:00
r = requests . get ( urlparse . urljoin ( self . userPath , ' user/ ' + str ( user_id ) ) , auth = self . auth , verify = self . verify )
2019-08-01 22:00:48 +00:00
self . printResponse ( r )
2020-01-31 18:10:45 +00:00
def addUser ( self , username = ' ' , password = ' ' , public_keys = ' ' , home_dir = ' ' , uid = 0 , gid = 0 , max_sessions = 0 , quota_size = 0 ,
2020-01-19 06:41:05 +00:00
quota_files = 0 , perms = [ ] , upload_bandwidth = 0 , download_bandwidth = 0 , status = 1 , expiration_date = 0 ,
subdirs_permissions = [ ] , allowed_ip = [ ] , denied_ip = [ ] , fs_provider = ' local ' , s3_bucket = ' ' , s3_region = ' ' ,
2020-01-31 18:04:00 +00:00
s3_access_key = ' ' , s3_access_secret = ' ' , s3_endpoint = ' ' , s3_storage_class = ' ' , s3_key_prefix = ' ' , gcs_bucket = ' ' ,
2020-02-19 21:39:30 +00:00
gcs_key_prefix = ' ' , gcs_storage_class = ' ' , gcs_credentials_file = ' ' , gcs_automatic_credentials = ' automatic ' ,
2020-03-13 16:28:55 +00:00
denied_login_methods = [ ] , virtual_folders = [ ] , denied_extensions = [ ] , allowed_extensions = [ ] ,
2020-03-13 18:13:58 +00:00
s3_upload_part_size = 0 , s3_upload_concurrency = 0 ) :
2019-08-07 21:41:10 +00:00
u = self . buildUserObject ( 0 , username , password , public_keys , home_dir , uid , gid , max_sessions ,
2019-12-29 16:21:25 +00:00
quota_size , quota_files , self . buildPermissions ( perms , subdirs_permissions ) , upload_bandwidth , download_bandwidth ,
2020-01-31 18:04:00 +00:00
status , expiration_date , allowed_ip , denied_ip , fs_provider , s3_bucket , s3_region , s3_access_key ,
s3_access_secret , s3_endpoint , s3_storage_class , s3_key_prefix , gcs_bucket , gcs_key_prefix , gcs_storage_class ,
2020-03-01 21:10:29 +00:00
gcs_credentials_file , gcs_automatic_credentials , denied_login_methods , virtual_folders , denied_extensions ,
2020-03-13 18:13:58 +00:00
allowed_extensions , s3_upload_part_size , s3_upload_concurrency )
2019-08-07 21:06:26 +00:00
r = requests . post ( self . userPath , json = u , auth = self . auth , verify = self . verify )
2019-08-01 22:00:48 +00:00
self . printResponse ( r )
2020-01-31 18:10:45 +00:00
def updateUser ( self , user_id , username = ' ' , password = ' ' , public_keys = ' ' , home_dir = ' ' , uid = 0 , gid = 0 , max_sessions = 0 ,
2020-01-19 06:41:05 +00:00
quota_size = 0 , quota_files = 0 , perms = [ ] , upload_bandwidth = 0 , download_bandwidth = 0 , status = 1 ,
expiration_date = 0 , subdirs_permissions = [ ] , allowed_ip = [ ] , denied_ip = [ ] , fs_provider = ' local ' ,
2020-01-19 22:23:09 +00:00
s3_bucket = ' ' , s3_region = ' ' , s3_access_key = ' ' , s3_access_secret = ' ' , s3_endpoint = ' ' , s3_storage_class = ' ' ,
2020-02-19 08:41:15 +00:00
s3_key_prefix = ' ' , gcs_bucket = ' ' , gcs_key_prefix = ' ' , gcs_storage_class = ' ' , gcs_credentials_file = ' ' ,
2020-03-01 21:10:29 +00:00
gcs_automatic_credentials = ' automatic ' , denied_login_methods = [ ] , virtual_folders = [ ] , denied_extensions = [ ] ,
2020-03-13 18:13:58 +00:00
allowed_extensions = [ ] , s3_upload_part_size = 0 , s3_upload_concurrency = 0 ) :
2019-08-07 21:41:10 +00:00
u = self . buildUserObject ( user_id , username , password , public_keys , home_dir , uid , gid , max_sessions ,
2019-12-29 16:21:25 +00:00
quota_size , quota_files , self . buildPermissions ( perms , subdirs_permissions ) , upload_bandwidth , download_bandwidth ,
2020-01-19 06:41:05 +00:00
status , expiration_date , allowed_ip , denied_ip , fs_provider , s3_bucket , s3_region , s3_access_key ,
2020-01-31 18:04:00 +00:00
s3_access_secret , s3_endpoint , s3_storage_class , s3_key_prefix , gcs_bucket , gcs_key_prefix , gcs_storage_class ,
2020-03-01 21:10:29 +00:00
gcs_credentials_file , gcs_automatic_credentials , denied_login_methods , virtual_folders , denied_extensions ,
2020-03-13 18:13:58 +00:00
allowed_extensions , s3_upload_part_size , s3_upload_concurrency )
2020-01-31 18:10:45 +00:00
r = requests . put ( urlparse . urljoin ( self . userPath , ' user/ ' + str ( user_id ) ) , json = u , auth = self . auth , verify = self . verify )
2019-08-01 22:00:48 +00:00
self . printResponse ( r )
def deleteUser ( self , user_id ) :
2020-01-31 18:10:45 +00:00
r = requests . delete ( urlparse . urljoin ( self . userPath , ' user/ ' + str ( user_id ) ) , auth = self . auth , verify = self . verify )
2019-08-01 22:00:48 +00:00
self . printResponse ( r )
2020-06-20 10:38:04 +00:00
def updateQuotaUsage ( self , username , used_quota_size , used_quota_files , mode ) :
req = { " username " : username , " used_quota_files " : used_quota_files , " used_quota_size " : used_quota_size }
r = requests . put ( self . updateUsedQuotaPath , params = { ' mode ' : mode } , json = req , auth = self . auth , verify = self . verify )
self . printResponse ( r )
def updateFolderQuotaUsage ( self , mapped_path , used_quota_size , used_quota_files , mode ) :
req = { " mapped_path " : mapped_path , " used_quota_files " : used_quota_files , " used_quota_size " : used_quota_size }
r = requests . put ( self . updateFolderUsedQuotaPath , params = { ' mode ' : mode } , json = req , auth = self . auth , verify = self . verify )
self . printResponse ( r )
2019-08-24 12:41:15 +00:00
def getConnections ( self ) :
2019-08-07 21:06:26 +00:00
r = requests . get ( self . activeConnectionsPath , auth = self . auth , verify = self . verify )
2019-08-01 22:00:48 +00:00
self . printResponse ( r )
2019-08-24 12:41:15 +00:00
def closeConnection ( self , connectionID ) :
2020-01-31 18:10:45 +00:00
r = requests . delete ( urlparse . urljoin ( self . activeConnectionsPath , ' connection/ ' + str ( connectionID ) ) , auth = self . auth )
2019-08-01 22:00:48 +00:00
self . printResponse ( r )
def getQuotaScans ( self ) :
2019-08-07 21:06:26 +00:00
r = requests . get ( self . quotaScanPath , auth = self . auth , verify = self . verify )
2019-08-01 22:00:48 +00:00
self . printResponse ( r )
def startQuotaScan ( self , username ) :
u = self . buildUserObject ( 0 , username )
2019-08-07 21:06:26 +00:00
r = requests . post ( self . quotaScanPath , json = u , auth = self . auth , verify = self . verify )
2019-08-01 22:00:48 +00:00
self . printResponse ( r )
2020-06-07 21:30:18 +00:00
def getFoldersQuotaScans ( self ) :
r = requests . get ( self . folderQuotaScanPath , auth = self . auth , verify = self . verify )
self . printResponse ( r )
def startFolderQuotaScan ( self , mapped_path ) :
f = { " mapped_path " : mapped_path }
r = requests . post ( self . folderQuotaScanPath , json = f , auth = self . auth , verify = self . verify )
self . printResponse ( r )
def addFolder ( self , mapped_path ) :
f = { " mapped_path " : mapped_path }
r = requests . post ( self . folderPath , json = f , auth = self . auth , verify = self . verify )
self . printResponse ( r )
def deleteFolder ( self , mapped_path ) :
r = requests . delete ( self . folderPath , params = { ' folder_path ' : mapped_path } , auth = self . auth , verify = self . verify )
self . printResponse ( r )
def getFolders ( self , limit = 100 , offset = 0 , order = ' ASC ' , mapped_path = ' ' ) :
r = requests . get ( self . folderPath , params = { ' limit ' : limit , ' offset ' : offset , ' order ' : order ,
' folder_path ' : mapped_path } , auth = self . auth , verify = self . verify )
self . printResponse ( r )
2019-08-08 08:01:33 +00:00
def getVersion ( self ) :
r = requests . get ( self . versionPath , auth = self . auth , verify = self . verify )
self . printResponse ( r )
2019-11-14 17:48:01 +00:00
def getProviderStatus ( self ) :
r = requests . get ( self . providerStatusPath , auth = self . auth , verify = self . verify )
self . printResponse ( r )
2020-02-02 21:20:39 +00:00
def dumpData ( self , output_file , indent ) :
r = requests . get ( self . dumpDataPath , params = { ' output_file ' : output_file , ' indent ' : indent } ,
auth = self . auth , verify = self . verify )
2019-12-27 22:12:44 +00:00
self . printResponse ( r )
2020-01-31 18:10:45 +00:00
def loadData ( self , input_file , scan_quota , mode ) :
r = requests . get ( self . loadDataPath , params = { ' input_file ' : input_file , ' scan_quota ' : scan_quota ,
' mode ' : mode } ,
2019-12-27 22:12:44 +00:00
auth = self . auth , verify = self . verify )
self . printResponse ( r )
2019-08-01 22:00:48 +00:00
2019-12-29 16:21:25 +00:00
class ConvertUsers :
def __init__ ( self , input_file , users_format , output_file , min_uid , max_uid , usernames , force_uid , force_gid ) :
self . input_file = input_file
self . users_format = users_format
self . output_file = output_file
self . min_uid = min_uid
self . max_uid = max_uid
self . usernames = usernames
self . force_uid = force_uid
self . force_gid = force_gid
self . SFTPGoUsers = [ ]
def setSFTPGoRestApi ( self , api ) :
self . SFTPGoRestAPI = api
def addUser ( self , user ) :
2020-01-31 18:10:45 +00:00
user [ ' id ' ] = len ( self . SFTPGoUsers ) + 1
2019-12-29 16:21:25 +00:00
print ( ' ' )
print ( ' New user imported: {} ' . format ( user ) )
print ( ' ' )
self . SFTPGoUsers . append ( user )
def saveUsers ( self ) :
if self . SFTPGoUsers :
2020-01-31 18:10:45 +00:00
data = { ' users ' : self . SFTPGoUsers }
2019-12-29 16:21:25 +00:00
jsonData = json . dumps ( data )
with open ( self . output_file , ' w ' ) as f :
f . write ( jsonData )
print ( )
print ( ' Number of users saved to " {} " : {} . You can import them using loaddata ' . format ( self . output_file ,
len ( self . SFTPGoUsers ) ) )
print ( )
sys . exit ( 0 )
else :
print ( ' No user imported ' )
sys . exit ( 1 )
def convert ( self ) :
2020-01-31 18:10:45 +00:00
if self . users_format == ' unix-passwd ' :
2019-12-29 16:21:25 +00:00
self . convertFromUnixPasswd ( )
2020-01-31 18:10:45 +00:00
elif self . users_format == ' pure-ftpd ' :
2019-12-29 16:21:25 +00:00
self . convertFromPureFTPD ( )
else :
self . convertFromProFTPD ( )
self . saveUsers ( )
2020-01-19 06:41:05 +00:00
def isUserValid ( self , username , uid ) :
2019-12-29 16:21:25 +00:00
if self . usernames and not username in self . usernames :
return False
if self . min_uid > = 0 and uid < self . min_uid :
return False
if self . max_uid > = 0 and uid > self . max_uid :
return False
return True
def convertFromUnixPasswd ( self ) :
days_from_epoch_time = time . time ( ) / 86400
for user in pwd . getpwall ( ) :
username = user . pw_name
password = user . pw_passwd
uid = user . pw_uid
gid = user . pw_gid
home_dir = user . pw_dir
status = 1
expiration_date = 0
2020-01-19 06:41:05 +00:00
if not self . isUserValid ( username , uid ) :
2019-12-29 16:21:25 +00:00
continue
if self . force_uid > = 0 :
uid = self . force_uid
if self . force_gid > = 0 :
gid = self . force_gid
# FIXME: if the passwords aren't in /etc/shadow they are probably DES encrypted and we don't support them
if password == ' x ' or password == ' * ' :
user_info = spwd . getspnam ( username )
password = user_info . sp_pwdp
if not password or password == ' !! ' :
2019-12-30 17:37:50 +00:00
print ( ' cannot import user " {} " without a password ' . format ( username ) )
2019-12-29 16:21:25 +00:00
continue
if user_info . sp_inact > 0 :
last_pwd_change_diff = days_from_epoch_time - user_info . sp_lstchg
if last_pwd_change_diff > user_info . sp_inact :
status = 0
if user_info . sp_expire > 0 :
expiration_date = user_info . sp_expire * 86400
permissions = self . SFTPGoRestAPI . buildPermissions ( [ ' * ' ] , [ ] )
self . addUser ( self . SFTPGoRestAPI . buildUserObject ( 0 , username , password , [ ] , home_dir , uid , gid , 0 , 0 , 0 ,
permissions , 0 , 0 , status , expiration_date ) )
def convertFromProFTPD ( self ) :
with open ( self . input_file , ' r ' ) as f :
for line in f :
fields = line . split ( ' : ' )
if len ( fields ) > 6 :
username = fields [ 0 ]
password = fields [ 1 ]
uid = int ( fields [ 2 ] )
gid = int ( fields [ 3 ] )
home_dir = fields [ 5 ]
if not self . isUserValid ( username , uid , gid ) :
continue
if self . force_uid > = 0 :
uid = self . force_uid
if self . force_gid > = 0 :
gid = self . force_gid
permissions = self . SFTPGoRestAPI . buildPermissions ( [ ' * ' ] , [ ] )
self . addUser ( self . SFTPGoRestAPI . buildUserObject ( 0 , username , password , [ ] , home_dir , uid , gid , 0 , 0 ,
0 , permissions , 0 , 0 , 1 , 0 ) )
2019-12-30 17:37:50 +00:00
def convertPureFTPDIP ( self , fields ) :
result = [ ]
if not fields :
return result
2020-01-31 18:10:45 +00:00
for v in fields . split ( ' , ' ) :
2019-12-30 17:37:50 +00:00
ip_mask = v . strip ( )
if not ip_mask :
continue
2020-01-31 18:10:45 +00:00
if ip_mask . count ( ' . ' ) < 3 and ip_mask . count ( ' : ' ) < 3 :
print ( ' cannot import pure-ftpd IP: {} ' . format ( ip_mask ) )
2019-12-30 17:37:50 +00:00
continue
2020-01-31 18:10:45 +00:00
if ' / ' not in ip_mask :
ip_mask + = ' /32 '
2019-12-30 17:37:50 +00:00
result . append ( ip_mask )
return result
2019-12-29 16:21:25 +00:00
def convertFromPureFTPD ( self ) :
with open ( self . input_file , ' r ' ) as f :
for line in f :
fields = line . split ( ' : ' )
2019-12-30 17:37:50 +00:00
if len ( fields ) > 16 :
2019-12-29 16:21:25 +00:00
username = fields [ 0 ]
password = fields [ 1 ]
uid = int ( fields [ 2 ] )
gid = int ( fields [ 3 ] )
home_dir = fields [ 5 ]
upload_bandwidth = 0
if fields [ 6 ] :
upload_bandwidth = int ( int ( fields [ 6 ] ) / 1024 )
download_bandwidth = 0
if fields [ 7 ] :
download_bandwidth = int ( int ( fields [ 7 ] ) / 1024 )
max_sessions = 0
if fields [ 10 ] :
max_sessions = int ( fields [ 10 ] )
quota_files = 0
if fields [ 11 ] :
quota_files = int ( fields [ 11 ] )
quota_size = 0
if fields [ 12 ] :
quota_size = int ( fields [ 12 ] )
2019-12-30 17:37:50 +00:00
allowed_ip = self . convertPureFTPDIP ( fields [ 15 ] )
denied_ip = self . convertPureFTPDIP ( fields [ 16 ] )
2019-12-29 16:21:25 +00:00
if not self . isUserValid ( username , uid , gid ) :
continue
if self . force_uid > = 0 :
uid = self . force_uid
if self . force_gid > = 0 :
gid = self . force_gid
permissions = self . SFTPGoRestAPI . buildPermissions ( [ ' * ' ] , [ ] )
self . addUser ( self . SFTPGoRestAPI . buildUserObject ( 0 , username , password , [ ] , home_dir , uid , gid ,
max_sessions , quota_size , quota_files , permissions ,
2019-12-30 17:37:50 +00:00
upload_bandwidth , download_bandwidth , 1 , 0 , allowed_ip ,
denied_ip ) )
2019-12-29 16:21:25 +00:00
2019-11-13 10:36:21 +00:00
def validDate ( s ) :
if not s :
return datetime . fromtimestamp ( 0 )
try :
2020-01-31 18:10:45 +00:00
return datetime . strptime ( s , ' % Y- % m- %d ' )
2019-11-13 10:36:21 +00:00
except ValueError :
2020-01-31 18:10:45 +00:00
msg = ' Not a valid date: " {0} " . ' . format ( s )
2019-11-13 10:36:21 +00:00
raise argparse . ArgumentTypeError ( msg )
def getDatetimeAsMillisSinceEpoch ( dt ) :
epoch = datetime . fromtimestamp ( 0 )
return int ( ( dt - epoch ) . total_seconds ( ) * 1000 )
2019-08-01 22:00:48 +00:00
def addCommonUserArguments ( parser ) :
parser . add_argument ( ' username ' , type = str )
2019-12-29 13:07:44 +00:00
parser . add_argument ( ' -P ' , ' --password ' , type = str , default = None , help = ' Default: %(default)s ' )
2020-05-15 18:08:53 +00:00
parser . add_argument ( ' -K ' , ' --public-keys ' , type = str , nargs = ' + ' , default = [ ] , help = ' Public keys or SSH user certificates. ' +
' Default: %(default)s ' )
2020-01-19 06:41:05 +00:00
parser . add_argument ( ' -H ' , ' --home-dir ' , type = str , default = ' ' , help = ' Default: %(default)s ' )
2019-08-08 10:03:24 +00:00
parser . add_argument ( ' --uid ' , type = int , default = 0 , help = ' Default: %(default)s ' )
parser . add_argument ( ' --gid ' , type = int , default = 0 , help = ' Default: %(default)s ' )
parser . add_argument ( ' -C ' , ' --max-sessions ' , type = int , default = 0 ,
help = ' Maximum concurrent sessions. 0 means unlimited. Default: %(default)s ' )
parser . add_argument ( ' -S ' , ' --quota-size ' , type = int , default = 0 ,
help = ' Maximum size allowed as bytes. 0 means unlimited. Default: %(default)s ' )
2020-01-31 18:10:45 +00:00
parser . add_argument ( ' -F ' , ' --quota-files ' , type = int , default = 0 , help = ' default: %(default)s ' )
2019-08-08 10:03:24 +00:00
parser . add_argument ( ' -G ' , ' --permissions ' , type = str , nargs = ' + ' , default = [ ] ,
2019-09-17 06:53:45 +00:00
choices = [ ' * ' , ' list ' , ' download ' , ' upload ' , ' overwrite ' , ' delete ' , ' rename ' , ' create_dirs ' ,
2019-12-25 17:20:19 +00:00
' create_symlinks ' , ' chmod ' , ' chown ' , ' chtimes ' ] , help = ' Permissions for the root directory '
+ ' (/). Default: %(default)s ' )
2020-02-19 21:39:30 +00:00
parser . add_argument ( ' -L ' , ' --denied-login-methods ' , type = str , nargs = ' + ' , default = [ ] ,
2020-04-09 21:32:42 +00:00
choices = [ ' ' , ' publickey ' , ' password ' , ' keyboard-interactive ' , ' publickey+password ' ,
' publickey+keyboard-interactive ' ] , help = ' Default: %(default)s ' )
2019-12-25 17:20:19 +00:00
parser . add_argument ( ' --subdirs-permissions ' , type = str , nargs = ' * ' , default = [ ] , help = ' Permissions for subdirs. '
2020-02-23 10:30:26 +00:00
+ ' For example: " /somedir::list,download " " /otherdir/subdir::* " Default: %(default)s ' )
parser . add_argument ( ' --virtual-folders ' , type = str , nargs = ' * ' , default = [ ] , help = ' Virtual folder mapping. For example: '
2020-06-07 21:30:18 +00:00
+ ' " /vpath::/home/adir " " /vpath::C: \a dir::[quota_file]::[quota_size] " . Quota parameters -1 means '
+ ' included inside user quota, 0 means unlimited. Ignored for non local filesystems. Default: %(default)s ' )
2019-08-08 10:03:24 +00:00
parser . add_argument ( ' -U ' , ' --upload-bandwidth ' , type = int , default = 0 ,
help = ' Maximum upload bandwidth as KB/s, 0 means unlimited. Default: %(default)s ' )
parser . add_argument ( ' -D ' , ' --download-bandwidth ' , type = int , default = 0 ,
help = ' Maximum download bandwidth as KB/s, 0 means unlimited. Default: %(default)s ' )
2019-11-13 10:36:21 +00:00
parser . add_argument ( ' --status ' , type = int , choices = [ 0 , 1 ] , default = 1 ,
help = ' User \' s status. 1 enabled, 0 disabled. Default: %(default)s ' )
2020-01-31 18:10:45 +00:00
parser . add_argument ( ' -E ' , ' --expiration-date ' , type = validDate , default = ' ' ,
2019-11-13 10:36:21 +00:00
help = ' Expiration date as YYYY-MM-DD, empty string means no expiration. Default: %(default)s ' )
2019-12-30 17:37:50 +00:00
parser . add_argument ( ' -Y ' , ' --allowed-ip ' , type = str , nargs = ' + ' , default = [ ] ,
help = ' Allowed IP/Mask in CIDR notation. For example " 192.168.2.0/24 " or " 2001:db8::/32 " . Default: %(default)s ' )
parser . add_argument ( ' -N ' , ' --denied-ip ' , type = str , nargs = ' + ' , default = [ ] ,
help = ' Denied IP/Mask in CIDR notation. For example " 192.168.2.0/24 " or " 2001:db8::/32 " . Default: %(default)s ' )
2020-03-01 21:10:29 +00:00
parser . add_argument ( ' --denied-extensions ' , type = str , nargs = ' * ' , default = [ ] , help = ' Denied file extensions case insensitive. '
+ ' The format is /dir::ext1,ext2. For example: " /somedir::.jpg,.png " " /otherdir/subdir::.zip,.rar " . ' +
' You have to set both denied and allowed extensions to update existing values or none to preserve them. ' +
' If you only set allowed or denied extensions the missing one is assumed to be an empty list. Default: %(default)s ' )
parser . add_argument ( ' --allowed-extensions ' , type = str , nargs = ' * ' , default = [ ] , help = ' Allowed file extensions case insensitive. '
+ ' The format is /dir::ext1,ext2. For example: " /somedir::.jpg,.png " " /otherdir/subdir::.zip,.rar " . ' +
' Default: %(default)s ' )
2020-01-31 18:04:00 +00:00
parser . add_argument ( ' --fs ' , type = str , default = ' local ' , choices = [ ' local ' , ' S3 ' , ' GCS ' ] ,
2020-01-19 06:41:05 +00:00
help = ' Filesystem provider. Default: %(default)s ' )
parser . add_argument ( ' --s3-bucket ' , type = str , default = ' ' , help = ' Default: %(default)s ' )
2020-01-19 22:23:09 +00:00
parser . add_argument ( ' --s3-key-prefix ' , type = str , default = ' ' , help = ' Virtual root directory. If non empty only this ' +
' directory and its contents will be available. Cannot start with " / " . For example " folder/subfolder/ " . ' +
' Default: %(default)s ' )
2020-01-19 06:41:05 +00:00
parser . add_argument ( ' --s3-region ' , type = str , default = ' ' , help = ' Default: %(default)s ' )
parser . add_argument ( ' --s3-access-key ' , type = str , default = ' ' , help = ' Default: %(default)s ' )
parser . add_argument ( ' --s3-access-secret ' , type = str , default = ' ' , help = ' Default: %(default)s ' )
parser . add_argument ( ' --s3-endpoint ' , type = str , default = ' ' , help = ' Default: %(default)s ' )
parser . add_argument ( ' --s3-storage-class ' , type = str , default = ' ' , help = ' Default: %(default)s ' )
2020-03-13 16:28:55 +00:00
parser . add_argument ( ' --s3-upload-part-size ' , type = int , default = 0 , help = ' The buffer size for multipart uploads (MB). ' +
' Zero means the default (5 MB). Minimum is 5. Default: %(default)s ' )
2020-03-13 18:13:58 +00:00
parser . add_argument ( ' --s3-upload-concurrency ' , type = int , default = 0 , help = ' How many parts are uploaded in parallel. ' +
' Zero means the default (2). Default: %(default)s ' )
2020-01-31 18:04:00 +00:00
parser . add_argument ( ' --gcs-bucket ' , type = str , default = ' ' , help = ' Default: %(default)s ' )
parser . add_argument ( ' --gcs-key-prefix ' , type = str , default = ' ' , help = ' Virtual root directory. If non empty only this ' +
' directory and its contents will be available. Cannot start with " / " . For example " folder/subfolder/ " . ' +
' Default: %(default)s ' )
parser . add_argument ( ' --gcs-storage-class ' , type = str , default = ' ' , help = ' Default: %(default)s ' )
parser . add_argument ( ' --gcs-credentials-file ' , type = str , default = ' ' , help = ' Default: %(default)s ' )
2020-02-19 08:41:15 +00:00
parser . add_argument ( ' --gcs-automatic-credentials ' , type = str , default = ' automatic ' , choices = [ ' explicit ' , ' automatic ' ] ,
help = ' If you provide a credentials file this argument will be setted to " explicit " . Default: %(default)s ' )
2019-08-01 22:00:48 +00:00
if __name__ == ' __main__ ' :
parser = argparse . ArgumentParser ( formatter_class = argparse . ArgumentDefaultsHelpFormatter )
2019-08-08 10:03:24 +00:00
parser . add_argument ( ' -b ' , ' --base-url ' , type = str , default = ' http://127.0.0.1:8080 ' ,
help = ' Base URL for SFTPGo REST API. Default: %(default)s ' )
parser . add_argument ( ' -a ' , ' --auth-type ' , type = str , default = None , choices = [ ' basic ' , ' digest ' ] ,
help = ' HTTP authentication type. Default: %(default)s ' )
2020-01-31 18:10:45 +00:00
parser . add_argument ( ' -u ' , ' --auth-user ' , type = str , default = ' ' ,
2019-08-08 12:20:42 +00:00
help = ' User for HTTP authentication. Default: %(default)s ' )
2019-08-08 10:03:24 +00:00
parser . add_argument ( ' -p ' , ' --auth-password ' , type = str , default = ' ' ,
2019-08-08 12:20:42 +00:00
help = ' Password for HTTP authentication. Default: %(default)s ' )
2019-08-08 10:03:24 +00:00
parser . add_argument ( ' -d ' , ' --debug ' , dest = ' debug ' , action = ' store_true ' )
2019-08-01 22:00:48 +00:00
parser . set_defaults ( debug = False )
2019-08-08 12:20:42 +00:00
parser . add_argument ( ' -i ' , ' --insecure ' , dest = ' secure ' , action = ' store_false ' ,
2019-08-08 10:03:24 +00:00
help = ' Set to false to ignore verifying the SSL certificate ' )
parser . set_defaults ( secure = True )
2020-01-31 18:10:45 +00:00
has_colors_default = pygments is not None and platform . system ( ) != ' Windows '
2020-01-12 13:54:41 +00:00
group = parser . add_mutually_exclusive_group ( required = False )
group . add_argument ( ' -t ' , ' --no-color ' , dest = ' no_color ' , action = ' store_true ' , default = ( not has_colors_default ) ,
2019-08-08 12:20:42 +00:00
help = ' Disable color highlight for JSON responses. You need python pygments module 1.5 or above to have highlighted output ' )
2020-01-12 13:54:41 +00:00
group . add_argument ( ' -c ' , ' --color ' , dest = ' no_color ' , action = ' store_false ' , default = has_colors_default ,
help = ' Enable color highlight for JSON responses. You need python pygments module 1.5 or above to have highlighted output ' )
parser . add_argument_group ( group )
2019-08-01 22:00:48 +00:00
2019-08-08 10:03:24 +00:00
subparsers = parser . add_subparsers ( dest = ' command ' , help = ' sub-command --help ' )
2019-08-01 22:00:48 +00:00
subparsers . required = True
2019-08-08 10:03:24 +00:00
parserAddUser = subparsers . add_parser ( ' add-user ' , help = ' Add a new SFTP user ' )
2019-08-01 22:00:48 +00:00
addCommonUserArguments ( parserAddUser )
2019-08-08 10:03:24 +00:00
parserUpdateUser = subparsers . add_parser ( ' update-user ' , help = ' Update an existing user ' )
parserUpdateUser . add_argument ( ' id ' , type = int , help = ' User \' s ID to update ' )
2019-08-01 22:00:48 +00:00
addCommonUserArguments ( parserUpdateUser )
2019-08-08 10:03:24 +00:00
parserDeleteUser = subparsers . add_parser ( ' delete-user ' , help = ' Delete an existing user ' )
parserDeleteUser . add_argument ( ' id ' , type = int , help = ' User \' s ID to delete ' )
2019-08-01 22:00:48 +00:00
2019-08-08 10:03:24 +00:00
parserGetUsers = subparsers . add_parser ( ' get-users ' , help = ' Returns an array with one or more SFTP users ' )
parserGetUsers . add_argument ( ' -L ' , ' --limit ' , type = int , default = 100 , choices = range ( 1 , 501 ) ,
help = ' Maximum allowed value is 500. Default: %(default)s ' , metavar = ' [1...500] ' )
parserGetUsers . add_argument ( ' -O ' , ' --offset ' , type = int , default = 0 , help = ' Default: %(default)s ' )
parserGetUsers . add_argument ( ' -U ' , ' --username ' , type = str , default = ' ' , help = ' Default: %(default)s ' )
parserGetUsers . add_argument ( ' -S ' , ' --order ' , type = str , choices = [ ' ASC ' , ' DESC ' ] , default = ' ASC ' ,
help = ' default: %(default)s ' )
2019-08-01 22:00:48 +00:00
2019-08-08 10:03:24 +00:00
parserGetUserByID = subparsers . add_parser ( ' get-user-by-id ' , help = ' Find user by ID ' )
2019-08-01 22:00:48 +00:00
parserGetUserByID . add_argument ( ' id ' , type = int )
2019-08-24 12:41:15 +00:00
parserGetConnections = subparsers . add_parser ( ' get-connections ' ,
help = ' Get the active users and info about their uploads/downloads ' )
2019-08-01 22:00:48 +00:00
2019-08-24 12:41:15 +00:00
parserCloseConnection = subparsers . add_parser ( ' close-connection ' , help = ' Terminate an active SFTP/SCP connection ' )
parserCloseConnection . add_argument ( ' connectionID ' , type = str )
2019-08-01 22:00:48 +00:00
2020-06-07 21:30:18 +00:00
parserGetQuotaScans = subparsers . add_parser ( ' get-quota-scans ' , help = ' Get the active quota scans for users home directories ' )
parserStartQuotaScan = subparsers . add_parser ( ' start-quota-scan ' , help = ' Start a new user quota scan ' )
addCommonUserArguments ( parserStartQuotaScan )
parserGetFolderQuotaScans = subparsers . add_parser ( ' get-folders-quota-scans ' , help = ' Get the active quota scans for folders ' )
parserStartFolderQuotaScan = subparsers . add_parser ( ' start-folder-quota-scan ' , help = ' Start a new folder quota scan ' )
parserStartFolderQuotaScan . add_argument ( ' folder_path ' , type = str )
parserGetFolders = subparsers . add_parser ( ' get-folders ' , help = ' Returns an array with one or more folders ' )
parserGetFolders . add_argument ( ' -L ' , ' --limit ' , type = int , default = 100 , choices = range ( 1 , 501 ) ,
help = ' Maximum allowed value is 500. Default: %(default)s ' , metavar = ' [1...500] ' )
parserGetFolders . add_argument ( ' -O ' , ' --offset ' , type = int , default = 0 , help = ' Default: %(default)s ' )
parserGetFolders . add_argument ( ' -P ' , ' --folder-path ' , type = str , default = ' ' , help = ' Default: %(default)s ' )
parserGetFolders . add_argument ( ' -S ' , ' --order ' , type = str , choices = [ ' ASC ' , ' DESC ' ] , default = ' ASC ' ,
help = ' default: %(default)s ' )
parserAddFolder = subparsers . add_parser ( ' add-folder ' , help = ' Add a new folder ' )
parserAddFolder . add_argument ( ' folder_path ' , type = str )
2019-08-01 22:00:48 +00:00
2020-06-07 21:30:18 +00:00
parserDeleteFolder = subparsers . add_parser ( ' delete-folder ' , help = ' Delete an existing folder ' )
parserDeleteFolder . add_argument ( ' folder_path ' , type = str )
2019-08-01 22:00:48 +00:00
2019-08-08 10:03:24 +00:00
parserGetVersion = subparsers . add_parser ( ' get-version ' , help = ' Get version details ' )
2019-08-08 08:01:33 +00:00
2019-11-14 17:48:01 +00:00
parserGetProviderStatus = subparsers . add_parser ( ' get-provider-status ' , help = ' Get data provider status ' )
2019-12-27 22:12:44 +00:00
parserDumpData = subparsers . add_parser ( ' dumpdata ' , help = ' Backup SFTPGo data serializing them as JSON ' )
parserDumpData . add_argument ( ' output_file ' , type = str )
2020-02-02 21:20:39 +00:00
parserDumpData . add_argument ( ' -I ' , ' --indent ' , type = int , choices = [ 0 , 1 ] , default = 0 ,
help = ' 0 means no indentation. 1 means format the output JSON. Default: %(default)s ' )
2019-12-27 22:12:44 +00:00
parserLoadData = subparsers . add_parser ( ' loaddata ' , help = ' Restore SFTPGo data from a JSON backup ' )
parserLoadData . add_argument ( ' input_file ' , type = str )
2019-12-29 13:07:44 +00:00
parserLoadData . add_argument ( ' -Q ' , ' --scan-quota ' , type = int , choices = [ 0 , 1 , 2 ] , default = 0 ,
2019-12-27 22:12:44 +00:00
help = ' 0 means no quota scan after a user is added/updated. 1 means always scan quota. 2 ' +
' means scan quota if the user has quota restrictions. Default: %(default)s ' )
2020-01-31 18:10:45 +00:00
parserLoadData . add_argument ( ' -M ' , ' --mode ' , type = int , choices = [ 0 , 1 ] , default = 0 ,
help = ' 0 means new users are added, existing users are updated. 1 means new users are added, ' +
' existing users are not modified. Default: %(default)s ' )
2019-12-27 22:12:44 +00:00
2020-06-20 10:38:04 +00:00
parserUpdateQuotaUsage = subparsers . add_parser ( ' update-quota-usage ' , help = ' Update the user used quota limits ' )
parserUpdateQuotaUsage . add_argument ( ' username ' , type = str )
parserUpdateQuotaUsage . add_argument ( ' -M ' , ' --mode ' , type = str , choices = [ " add " , " reset " ] , default = " reset " ,
help = ' the update mode specifies if the given quota usage values should be added or ' +
' replace the current ones. Default: %(default)s ' )
parserUpdateQuotaUsage . add_argument ( ' -S ' , ' --used_quota_size ' , type = int , default = 0 , help = ' Default: %(default)s ' )
parserUpdateQuotaUsage . add_argument ( ' -F ' , ' --used_quota_files ' , type = int , default = 0 , help = ' Default: %(default)s ' )
parserUpdateFolderQuotaUsage = subparsers . add_parser ( ' update-folder-quota-usage ' , help = ' Update the folder used quota limits ' )
parserUpdateFolderQuotaUsage . add_argument ( ' folder_path ' , type = str )
parserUpdateFolderQuotaUsage . add_argument ( ' -M ' , ' --mode ' , type = str , choices = [ " add " , " reset " ] , default = " reset " ,
help = ' the update mode specifies if the given quota usage values should be added or ' +
' replace the current ones. Default: %(default)s ' )
parserUpdateFolderQuotaUsage . add_argument ( ' -S ' , ' --used_quota_size ' , type = int , default = 0 , help = ' Default: %(default)s ' )
parserUpdateFolderQuotaUsage . add_argument ( ' -F ' , ' --used_quota_files ' , type = int , default = 0 , help = ' Default: %(default)s ' )
2020-01-31 18:10:45 +00:00
parserConvertUsers = subparsers . add_parser ( ' convert-users ' , help = ' Convert users to a JSON format suitable to use ' +
' with loadddata ' )
2019-12-29 16:21:25 +00:00
supportedUsersFormats = [ ]
help_text = ' '
if pwd is not None :
2020-01-31 18:10:45 +00:00
supportedUsersFormats . append ( ' unix-passwd ' )
2019-12-29 16:21:25 +00:00
help_text = ' To import from unix-passwd format you need the permission to read /etc/shadow that is typically granted to the root user only '
2020-01-31 18:10:45 +00:00
supportedUsersFormats . append ( ' pure-ftpd ' )
supportedUsersFormats . append ( ' proftpd ' )
2019-12-29 16:21:25 +00:00
parserConvertUsers . add_argument ( ' input_file ' , type = str )
parserConvertUsers . add_argument ( ' users_format ' , type = str , choices = supportedUsersFormats , help = help_text )
parserConvertUsers . add_argument ( ' output_file ' , type = str )
parserConvertUsers . add_argument ( ' --min-uid ' , type = int , default = - 1 , help = ' if >= 0 only import users with UID greater ' +
' or equal to this value. Default: %(default)s ' )
parserConvertUsers . add_argument ( ' --max-uid ' , type = int , default = - 1 , help = ' if >= 0 only import users with UID lesser ' +
' or equal to this value. Default: %(default)s ' )
parserConvertUsers . add_argument ( ' --usernames ' , type = str , nargs = ' + ' , default = [ ] , help = ' Only import users with these ' +
' usernames. Default: %(default)s ' )
parserConvertUsers . add_argument ( ' --force-uid ' , type = int , default = - 1 , help = ' if >= 0 the imported users will have this UID in SFTPGo. Default: %(default)s ' )
parserConvertUsers . add_argument ( ' --force-gid ' , type = int , default = - 1 , help = ' if >= 0 the imported users will have this GID in SFTPGp. Default: %(default)s ' )
2019-08-01 22:00:48 +00:00
args = parser . parse_args ( )
2019-08-08 12:20:42 +00:00
api = SFTPGoApiRequests ( args . debug , args . base_url , args . auth_type , args . auth_user , args . auth_password , args . secure ,
args . no_color )
2019-08-01 22:00:48 +00:00
2019-08-08 10:03:24 +00:00
if args . command == ' add-user ' :
2019-11-13 10:36:21 +00:00
api . addUser ( args . username , args . password , args . public_keys , args . home_dir , args . uid , args . gid , args . max_sessions ,
args . quota_size , args . quota_files , args . permissions , args . upload_bandwidth , args . download_bandwidth ,
2019-12-30 17:37:50 +00:00
args . status , getDatetimeAsMillisSinceEpoch ( args . expiration_date ) , args . subdirs_permissions , args . allowed_ip ,
2020-01-19 06:41:05 +00:00
args . denied_ip , args . fs , args . s3_bucket , args . s3_region , args . s3_access_key , args . s3_access_secret ,
2020-01-31 18:04:00 +00:00
args . s3_endpoint , args . s3_storage_class , args . s3_key_prefix , args . gcs_bucket , args . gcs_key_prefix ,
2020-02-19 21:39:30 +00:00
args . gcs_storage_class , args . gcs_credentials_file , args . gcs_automatic_credentials ,
2020-03-13 16:28:55 +00:00
args . denied_login_methods , args . virtual_folders , args . denied_extensions , args . allowed_extensions ,
2020-03-13 18:13:58 +00:00
args . s3_upload_part_size , args . s3_upload_concurrency )
2019-08-08 10:03:24 +00:00
elif args . command == ' update-user ' :
2019-11-13 10:36:21 +00:00
api . updateUser ( args . id , args . username , args . password , args . public_keys , args . home_dir , args . uid , args . gid ,
args . max_sessions , args . quota_size , args . quota_files , args . permissions , args . upload_bandwidth ,
2019-12-25 17:20:19 +00:00
args . download_bandwidth , args . status , getDatetimeAsMillisSinceEpoch ( args . expiration_date ) ,
2020-01-19 06:41:05 +00:00
args . subdirs_permissions , args . allowed_ip , args . denied_ip , args . fs , args . s3_bucket , args . s3_region ,
2020-01-19 22:23:09 +00:00
args . s3_access_key , args . s3_access_secret , args . s3_endpoint , args . s3_storage_class ,
2020-01-31 18:04:00 +00:00
args . s3_key_prefix , args . gcs_bucket , args . gcs_key_prefix , args . gcs_storage_class ,
2020-02-23 10:30:26 +00:00
args . gcs_credentials_file , args . gcs_automatic_credentials , args . denied_login_methods ,
2020-03-13 18:13:58 +00:00
args . virtual_folders , args . denied_extensions , args . allowed_extensions , args . s3_upload_part_size ,
args . s3_upload_concurrency )
2019-08-08 10:03:24 +00:00
elif args . command == ' delete-user ' :
2019-08-01 22:00:48 +00:00
api . deleteUser ( args . id )
2019-08-08 10:03:24 +00:00
elif args . command == ' get-users ' :
2019-08-01 22:00:48 +00:00
api . getUsers ( args . limit , args . offset , args . order , args . username )
2019-08-08 10:03:24 +00:00
elif args . command == ' get-user-by-id ' :
2019-08-01 22:00:48 +00:00
api . getUserByID ( args . id )
2019-08-24 12:41:15 +00:00
elif args . command == ' get-connections ' :
api . getConnections ( )
elif args . command == ' close-connection ' :
api . closeConnection ( args . connectionID )
2019-08-08 10:03:24 +00:00
elif args . command == ' get-quota-scans ' :
2019-08-01 22:00:48 +00:00
api . getQuotaScans ( )
2019-08-08 10:03:24 +00:00
elif args . command == ' start-quota-scan ' :
2019-08-01 22:00:48 +00:00
api . startQuotaScan ( args . username )
2020-06-07 21:30:18 +00:00
elif args . command == ' get-folders ' :
api . getFolders ( args . limit , args . offset , args . order , args . folder_path )
elif args . command == ' add-folder ' :
api . addFolder ( args . folder_path )
elif args . command == ' delete-folder ' :
api . deleteFolder ( args . folder_path )
elif args . command == ' get-folders-quota-scans ' :
api . getFoldersQuotaScans ( )
elif args . command == ' start-folder-quota-scan ' :
api . startFolderQuotaScan ( args . folder_path )
2019-08-08 10:03:24 +00:00
elif args . command == ' get-version ' :
2019-08-08 08:01:33 +00:00
api . getVersion ( )
2019-11-14 17:48:01 +00:00
elif args . command == ' get-provider-status ' :
api . getProviderStatus ( )
2019-12-29 16:21:25 +00:00
elif args . command == ' dumpdata ' :
2020-02-02 21:20:39 +00:00
api . dumpData ( args . output_file , args . indent )
2019-12-29 16:21:25 +00:00
elif args . command == ' loaddata ' :
2020-01-31 18:10:45 +00:00
api . loadData ( args . input_file , args . scan_quota , args . mode )
2020-06-20 10:38:04 +00:00
elif args . command == ' update-quota-usage ' :
api . updateQuotaUsage ( args . username , args . used_quota_size , args . used_quota_files , args . mode )
elif args . command == ' update-folder-quota-usage ' :
api . updateFolderQuotaUsage ( args . folder_path , args . used_quota_size , args . used_quota_files , args . mode )
2019-12-29 16:21:25 +00:00
elif args . command == ' convert-users ' :
convertUsers = ConvertUsers ( args . input_file , args . users_format , args . output_file , args . min_uid , args . max_uid ,
args . usernames , args . force_uid , args . force_gid )
convertUsers . setSFTPGoRestApi ( api )
convertUsers . convert ( )