Skip to content

Commit

Permalink
Added password prompt when omitted in config
Browse files Browse the repository at this point in the history
The password prompt will be shown on demand and the password will be cached (as long as it is correct) until Sublime Text is closed
Fixes #18
  • Loading branch information
Aiq0 authored and HexRx committed Oct 7, 2022
1 parent b1e78ba commit 84da0ce
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 17 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ Minimal `simple-ftp-deploy.json` file:
}
```

**Note:** Password is optional. If omitted, you will be asked for it once needed.

### Format
The format is [JSON](https://www.json.org), so every property consists of a key-value pair:
```json
Expand Down Expand Up @@ -77,8 +79,8 @@ The port of the FTP server.
`"username"` *string*
The username.

`"password"` *string*
The password.
`"password"` *string, optional*
The password. If not given, you will be asked for it once needed.

`"rootDirectory"` *string, optional (default: `"/"`)*
The FTP path to deploy.
Expand Down
71 changes: 56 additions & 15 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@
import sys
import time

REQUIRED_FIELDS = ['host', 'username', 'password']
REQUIRED_FIELDS = ['host', 'username']

CONFIG_FILE_NAME = 'simple-ftp-deploy.json'

FTP_SESSIONS = []

SAVED_LOGINS = {}

def ignored(path, config):
filename, extension = os.path.splitext(path)

Expand Down Expand Up @@ -128,7 +130,13 @@ def __init__(self, config):
self.host = config.get('host')
self.port = config.get('port', 21)
self.username = config.get('username')
self.password = config.get('password')

if not config.get('password'):
if (config.get('host'), config.get('port', 21), config.get('username')) in SAVED_LOGINS:
self.password = SAVED_LOGINS[(self.host, self.port, self.username)]
else:
self.password = config.get('password')

self.rootDir = config.get('rootDirectory', '')
self.timeout = config.get('connectionTimeout', 600)
self.TLS = config.get('useTLS', False)
Expand Down Expand Up @@ -187,7 +195,7 @@ def connect(self):
session['timestamp'] = time.time()

# As the session is ready to use, we are done
return
return True

# Create new session
if self.TLS:
Expand All @@ -211,7 +219,7 @@ def connect(self):
self.session.connect(self.host, self.port)
except ftplib.all_errors as e:
error('Could not connect to ' + self.host + ':' + str(self.port) + '\n' + str(e))
return
return False

# Secure with TLS
if self.TLS:
Expand All @@ -226,8 +234,12 @@ def connect(self):
try:
self.session.login(self.username, self.password)
except ftplib.all_errors as e:
# If it happened from saved logins, discard it, so it would ask for new password again
if (self.host, self.port, self.username) in SAVED_LOGINS:
SAVED_LOGINS.pop((self.host, self.port, self.username))

error('Could not login to ' + self.host + ':' + str(self.port) + '\n' + str(e))
return
return False

end = time.time()

Expand All @@ -246,6 +258,8 @@ def connect(self):
'session': self.session
})

return True

def parsePath(self, rootDir, fullPath):
# Remove full path and remove \
localFilePath = os.path.dirname(fullPath).replace(rootDir, '')[1:]
Expand Down Expand Up @@ -333,6 +347,9 @@ def set(self, name, value):
def get(self, name, defaultValue = None):
return self.config[name] if self.config and name in self.config else defaultValue

def has(self, name):
return self.config and name in self.config

# Save file event listener
class EventListener(sublime_plugin.EventListener):
def on_post_save_async(self, view):
Expand All @@ -353,13 +370,24 @@ def on_post_save_async(self, view):

if not ignored(filename, config):
# Upload
ftp = FTP(config)
ftp.connect()
ftp.upload(folder, filename)
def run():
ftp = FTP(config)
if ftp.connect():
ftp.upload(folder, filename)

process_triggers(config.get('triggers', []), folder, filename, 'save', {'ftp': ftp, 'config': config, 'sublime': sublime, 'msg': msg, 'error': error, 'ask': ask})
process_triggers(config.get('triggers', []), folder, filename, 'save', {'ftp': ftp, 'config': config, 'sublime': sublime, 'msg': msg, 'error': error, 'ask': ask})

ftp.exit()
ftp.exit()

if not config.has('password') and (config.get('host'), config.get('port', 21), config.get('username')) not in SAVED_LOGINS:
def on_password_done(input):
SAVED_LOGINS[(config.get('host'), config.get('port', 21), config.get('username'))] = input

run()

window.show_input_panel('FTP Password', '', on_password_done, None, None)
else:
run()

def on_post_window_command(self, window, command, args):
if not window.project_data():
Expand All @@ -385,13 +413,26 @@ def on_post_window_command(self, window, command, args):

if not ignored(filename, config):
# Delete
ftp = FTP(config)
ftp.connect()
ftp.delete(folder, filename)
def run():
ftp = FTP(config)
if ftp.connect():
ftp.delete(folder, filename)

process_triggers(config.get('triggers', []), folder, filename, 'delete', {'ftp': ftp, 'config': config, 'sublime': sublime, 'msg': msg, 'error': error, 'ask': ask})
process_triggers(config.get('triggers', []), folder, filename, 'delete', {'ftp': ftp, 'config': config, 'sublime': sublime, 'msg': msg, 'error': error, 'ask': ask})

ftp.exit()
ftp.exit()

# Upload
if not config.has('password') and (config.get('host'), config.get('port', 21), config.get('username')) not in SAVED_LOGINS:
def on_password_done(input):
SAVED_LOGINS[(config.get('host'), config.get('port', 21), config.get('username'))] = input

run()


window.show_input_panel('FTP Password', '', on_password_done, None, None)
else:
run()

break

Expand Down
3 changes: 3 additions & 0 deletions messages.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"1.8.0": "messages/1.8.0.md"
}
5 changes: 5 additions & 0 deletions messages/1.8.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# 1.8.0 - Added option to enter password at runtime

## New features
* If password is omitted in config, password prompt will appear once it is needed
* Password entered to password prompt is cached until you close Sublime Text. This means that you will have to enter password only once (as long as it is correct)

0 comments on commit 84da0ce

Please sign in to comment.