Skip to content

Commit 9b0c3d9

Browse files
committedMar 31, 2017
init
1 parent 37bd2f2 commit 9b0c3d9

18 files changed

+200
-46
lines changed
 

‎config.template.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ let config = {
2121
/**
2222
* Set to true to get more information for errors and stuff like that
2323
*/
24-
'debug': false
24+
'development': false
2525
}
2626

2727
module.exports = config

‎lang/en.json

+9-3
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,15 @@
5353
"mtime": "Last modified",
5454
"no": "No",
5555
"password": "Password",
56-
"password.description": "Leave empty if you don't want to change it",
56+
"password.description": "Leave empty if you don't want to change it. Notice: The password will be stored as cleartext in db. However, somebody must have access to the server disk to read this.",
5757
"permissions": "Permissions",
5858
"progress": "Progress",
5959
"save.edited": "Save edited",
6060
"saved": "Saved",
6161
"server": "Server",
6262
"server.add": "Add new server",
6363
"server.auth": "Authentication",
64-
"server.auth.keyfile": "PPK Keyfile (Not yet implemented)",
64+
"server.auth.keyfile": "PPK Keyfile",
6565
"server.auth.normal": "Username + Password",
6666
"server.connect": "Connect",
6767
"server.encryption": "Encryption",
@@ -102,5 +102,11 @@
102102
"user.add": "Add new user",
103103
"usermanager": "Usermanager",
104104
"username": "Username",
105-
"yes": "Yes"
105+
"yes": "Yes",
106+
"server.auth.keyfile.passphrase": "Keyfile password",
107+
"server.auth.keyfile.description": "Paste the contents of the file in here",
108+
"update.available" : "Update available",
109+
"update.available.modal" : "There is a new release for this application. You have {currentVersion} and the newest release is {latestVersion}. Make sure to always have a backup before applying any update. With the click on the accept button the application will shut down, downloading the update, apply the update and restart the application automatically. However, if something goes wrong you should have access to the command line to fix the issues per hand.",
110+
"coreupdate.started" : "Update started, application will restart automatically when all is done",
111+
"coreupdate.error" : "Cannot execute automatic update. OS doesn't support this method or development mode is enabled"
106112
}

‎public/scripts/src/form.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ gl.form.create = function (container, formName, fields, onSubmit, onCancel, valu
6262
$input.val(currentValue)
6363
}
6464
break
65+
case 'file':
66+
$input = $('<input type="file" class="form-control" name="' + fieldName + '">')
67+
break
6568
case 'select':
6669
let name = fieldName
6770
if (field.multiple) name += '[]'
@@ -119,7 +122,7 @@ gl.form.create = function (container, formName, fields, onSubmit, onCancel, valu
119122
}
120123
}
121124
}
122-
const $btn = $('<div><span data-name="save" data-translate="save" class="btn btn-info submit-form"></span></div>')
125+
const $btn = $('<div><span data-name="save" data-translate="save" class="btn btn-info submit-form btn-accept"></span></div>')
123126
if (Object.keys(values).length) {
124127
$btn.children().attr('data-translate', 'save.edited')
125128
$btn.append('&nbsp;<span data-translate="cancel.edit" class="btn btn-default cancel"></span>')
@@ -148,5 +151,6 @@ gl.form.create = function (container, formName, fields, onSubmit, onCancel, valu
148151
}
149152
})
150153
}).trigger('change')
154+
gl.textareaAutoheight($form)
151155
return $form
152156
}

‎public/scripts/src/global.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ gl.modal = function (header, body, footer, closeCallback) {
8585
gl.modalConfirm = function (body, callback) {
8686
const $footer = $('<div>')
8787
$footer
88-
.append('<span class="btn btn-info accept" data-translate="modal.confirm.accept"></span>')
88+
.append('<span class="btn btn-info accept btn-accept" data-translate="modal.confirm.accept"></span>')
8989
.append('<span class="btn btn-primary cancel" data-translate="modal.confirm.cancel"></span>')
9090
$footer.find('.accept').on('click', function () {
9191
callback(true)
@@ -172,6 +172,19 @@ gl.humanFilesize = function (bytes) {
172172
return bytes.toFixed(2) + map[i]
173173
}
174174

175+
/**
176+
* Initialize all textarea autoheights
177+
* @param {JQuery} container
178+
*/
179+
gl.textareaAutoheight = function (container) {
180+
container.find('textarea.autoheight').each(function () {
181+
this.setAttribute('style', 'height:' + (Math.max(20, this.scrollHeight)) + 'px;overflow-y:hidden;')
182+
}).addClass('autoheight-activated').off('input.ah focus.ah').on('input.ah focus.ah', function () {
183+
this.style.height = 'auto'
184+
this.style.height = (Math.max(20, this.scrollHeight)) + 'px'
185+
}).triggerHandler('input')
186+
}
187+
175188
// on document ready
176189
$(function () {
177190
gl.lang.setLanguageByNavigator()

‎public/stylesheets/src/page.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ html {
1616
margin: 0;
1717
}
1818

19-
form .submit-form {
19+
.btn-accept {
2020
&:before {
2121
@include glyphicon;
2222
content: "\e013";

‎public/tpl/menu-top.html

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
<div class="inline-block">
2323
<a class="btn btn-default dropdown-toggle btn-sm" href="https://www.paypal.me/brainfoolong" target="_blank"><span data-translate="donate" data-translate-property="data-tooltip,donate.tooltip"></span></a>
2424
</div>
25+
<div class="inline-block require-admin update-available hidden">
26+
<button class="btn btn-success btn-sm" type="button"><span data-translate="update.available"></span></button>
27+
</div>
2528
<div class="inline-block">
2629
<button class="btn btn-default dropdown-toggle btn-sm template-load-trigger" type="button" data-template="logout" data-container="#wrapper"><span data-translate="logout"></span></button>
2730
</div>

‎public/tpl/servermanager.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@
1515
</div>
1616
</div>
1717
<div class="center"></div>
18-
<div class="right">
18+
<div class="right require-admin">
1919
<div class="form form-general overflow-auto"></div>
2020
</div>

‎public/tpl/src/menu-top.js

+30
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,34 @@
11
'use strict';
22
(function () {
3+
const $tpl = $('.template-menu-top')
4+
let systemStatus = null
35

6+
// interval to check for new version
7+
const getSystemStatus = function () {
8+
gl.socket.send('getSystemStatus', null, function (data) {
9+
if (data.latestVersion) {
10+
systemStatus = data
11+
if (data.latestVersion !== data.currentVersion) {
12+
$tpl.find('.update-available').removeClass('hidden')
13+
}
14+
}
15+
})
16+
}
17+
getSystemStatus()
18+
setInterval(getSystemStatus, 10 * 1000)
19+
20+
$tpl.on('click', '.update-available', function () {
21+
gl.modalConfirm(gl.t('update.available.modal', systemStatus, true), function (result) {
22+
if (result === true) {
23+
gl.note('coreupdate.started')
24+
gl.socket.send('doCoreUpdate', null, function (result) {
25+
if (result === true) {
26+
27+
} else {
28+
gl.note('coreupdate.error')
29+
}
30+
})
31+
}
32+
})
33+
})
434
})()

‎public/tpl/src/servermanager.js

+17-3
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,30 @@
3636
'username': {
3737
'type': 'text',
3838
'label': 'username',
39-
'showIf': function (fields) {
40-
return fields.auth.val() === 'normal'
41-
}
39+
'required': true
4240
},
4341
'password': {
4442
'type': 'password',
4543
'label': 'password',
4644
'showIf': function (fields) {
4745
return fields.auth.val() === 'normal'
4846
}
47+
},
48+
'keyfile': {
49+
'type': 'textarea',
50+
'label': 'server.auth.keyfile',
51+
'description': 'server.auth.keyfile.description',
52+
'showIf': function (fields) {
53+
return fields.auth.val() === 'keyfile'
54+
}
55+
},
56+
'keyfile_passphrase': {
57+
'type': 'password',
58+
'label': 'server.auth.keyfile.passphrase',
59+
'description': 'password.description',
60+
'showIf': function (fields) {
61+
return fields.auth.val() === 'keyfile'
62+
}
4963
}
5064
}
5165
}

‎src/actions/doCoreUpdate.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict'
2+
3+
const path = require('path')
4+
const os = require('os')
5+
const exec = require('child_process').exec
6+
const config = require(path.join(__dirname, '../config'))
7+
8+
const action = {}
9+
10+
/**
11+
* Require admin
12+
* @type {boolean}
13+
*/
14+
action.requireAdmin = true
15+
16+
/**
17+
* Execute the action
18+
* @param {WebSocketUser} user
19+
* @param {*} message
20+
* @param {function} callback
21+
*/
22+
action.execute = function (user, message, callback) {
23+
if (os.platform() !== 'linux' || config.development) {
24+
callback(false)
25+
return
26+
}
27+
const dir = path.join(__dirname, '../..')
28+
exec('cd ' + dir + ' && ./wfc stop && node src/main.js update-core && ./wfc start', null, function () {
29+
callback(true)
30+
})
31+
}
32+
33+
module.exports = action

‎src/actions/getServers.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@ action.requireUser = true
1818
* @param {function} callback
1919
*/
2020
action.execute = function (user, message, callback) {
21-
callback(db.get('servers').cloneDeep().value())
21+
const servers = db.get('servers').cloneDeep().value()
22+
// strip out sensible data
23+
if (servers) {
24+
for (let i in servers) {
25+
delete servers[i].keyfile_passphrase
26+
delete servers[i].password
27+
}
28+
}
29+
callback(servers)
2230
}
2331

2432
module.exports = action

‎src/actions/getSystemStatus.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ action.requireUser = false
2020
action.execute = function (user, message, callback) {
2121
callback({
2222
'installed': db.get('users').size().value() > 0,
23-
'version': require(path.join(__dirname, '../core')).latestVersion
23+
'latestVersion': require(path.join(__dirname, '../core')).latestVersion,
24+
'currentVersion': require(path.join(__dirname, '../../package')).version,
25+
'development': require(path.join(__dirname, '../config')).development
2426
})
2527
}
2628

‎src/actions/servermanagerFormSubmit.js

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ action.execute = function (user, message, callback) {
3131
'id': db.getNextId()
3232
}
3333
}
34+
if (formData.password.length <= 0) {
35+
delete formData.password
36+
}
37+
if (formData.keyfile_passphrase.length <= 0) {
38+
delete formData.keyfile_passphrase
39+
}
3440
// simply merging data from form into data object
3541
extend(true, storedData, formData)
3642
Server.get(storedData.id).setServerData(storedData)

‎src/config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const fs = require('fs')
1010
let config = {
1111
'host': null,
1212
'port': 4340,
13-
'debug': false
13+
'development': false
1414
}
1515

1616
// load config.js if exist

‎src/core.js

+24-7
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,44 @@
11
'use strict'
22

33
const request = require('request')
4+
const path = require('path')
45

56
/**
67
* Core
78
* @type {object}
89
*/
910
const core = {}
1011

11-
/** @type {string} */
12-
core.latestVersion = ''
12+
/** @type {string|null} */
13+
core.latestVersion = null
14+
15+
/** @type {string|null} */
16+
core.latestVersionZip = null
1317

1418
/**
1519
* Fetch latest version for the core
20+
* @param {function=} callback
1621
*/
17-
core.fetchLatestVersion = function () {
18-
request('https://raw.githubusercontent.com/brainfoolong/web-ftp-client/master/package.json', function (error, response, body) {
22+
core.fetchLatestVersion = function (callback) {
23+
const pkg = require(path.join(__dirname, '../package'))
24+
request({
25+
url: 'https://api.github.com/repos/brainfoolong/' + pkg.rame + '/releases',
26+
headers: {
27+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
28+
}
29+
}, function (error, response, body) {
1930
if (!error) {
20-
const manifest = JSON.parse(body)
21-
if (manifest && manifest.version) {
22-
core.latestVersion = manifest.version
31+
const releases = JSON.parse(body)
32+
if (releases) {
33+
releases.sort(function (a, b) {
34+
return a.id < b.id
35+
})
36+
const release = releases.shift()
37+
core.latestVersion = release.tag_name
38+
core.latestVersionZip = release.zipball_url
2339
}
2440
}
41+
callback()
2542
})
2643
}
2744

‎src/ftpServer.js

+17-6
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ function FtpServer (id) {
6868
})
6969
}
7070
if (serverData.protocol === 'sftp') {
71+
const connectData = {
72+
host: serverData.host,
73+
port: serverData.port
74+
}
75+
if (typeof serverData.username !== 'undefined' && serverData.username.length > 0) {
76+
connectData.username = serverData.username
77+
}
78+
if (typeof serverData.password !== 'undefined' && serverData.password.length > 0) {
79+
connectData.password = serverData.password
80+
}
81+
if (typeof serverData.keyfile !== 'undefined' && serverData.keyfile.trim().length > 0) {
82+
connectData.privateKey = serverData.keyfile.trim()
83+
}
84+
if (typeof serverData.keyfile_passphrase !== 'undefined' && serverData.keyfile_passphrase.length > 0) {
85+
connectData.passphrase = serverData.keyfile_passphrase
86+
}
7187
self.sshClient = new SshClient()
7288
self.sshClient.on('ready', function () {
7389
self.server.log('log.ftpserver.ready')
@@ -88,12 +104,7 @@ function FtpServer (id) {
88104
self.server.logError(err)
89105
}).on('end', function () {
90106
self.disconnect()
91-
}).connect({
92-
host: serverData.host,
93-
port: serverData.port,
94-
username: serverData.username,
95-
password: serverData.password
96-
})
107+
}).connect(connectData)
97108
}
98109
}
99110
/**

‎src/logs.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ logs.log = function (server, message, params, type) {
5555
logs.logError = function (server, err) {
5656
const e = new Error(err.message)
5757
let msg = e.message
58-
if (require(path.join(__dirname, 'config.js')).debug) {
58+
if (require(path.join(__dirname, 'config.js')).development) {
5959
msg += ' | STACK: ' + e.stack
6060
}
6161
logs.log(server, msg, null, 'error')

‎src/main.js

+25-18
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,31 @@ if (mode === 'start') {
2424
if (mode === 'update-core') {
2525
const request = require('request')
2626
const fs = require('fs')
27-
const fstools = require(path.join(__dirname, 'fstools'))
27+
const fstools = require(path.join(__dirname, 'src/fstools'))
2828
const unzip = require('unzip')
2929
const dir = path.resolve(__dirname, '..')
30-
request('https://codeload.github.com/brainfoolong/web-ftp-client/zip/master', function () {
31-
fs.createReadStream(dir + '/master.zip').pipe(unzip.Parse()).on('entry', function (entry) {
32-
const fileName = entry.path.split('/').slice(1).join('/')
33-
if (!fileName.length) return
34-
const path = dir + '/' + fileName
35-
if (entry.type === 'Directory') {
36-
if (!fs.existsSync(path)) fs.mkdirSync(path, fstools.defaultMask)
37-
entry.autodrain()
38-
} else {
39-
entry.pipe(fs.createWriteStream(path, {'mode': fstools.defaultMask}))
40-
}
41-
}).on('close', function () {
42-
process.stdout.write('Application successfully updated\n')
43-
fs.unlinkSync(dir + '/master.zip')
44-
process.exit(0)
45-
})
46-
}).pipe(fs.createWriteStream(dir + '/master.zip'))
30+
const localZipFile = path.join(dir, path.dirname(dir) + '.zip')
31+
const core = require(path.join(__dirname, 'src/core'))
32+
33+
core.fetchLatestVersion(function () {
34+
request(core.latestVersionZip, function () {
35+
fs.createReadStream(localZipFile).pipe(unzip.Parse()).on('entry', function (entry) {
36+
const fileName = entry.path
37+
if (!fileName.length) return
38+
const filepath = path.join(dir, fileName)
39+
if (filepath === '') {
40+
if (entry.type === 'Directory') {
41+
if (!fs.existsSync(filepath)) fs.mkdirSync(filepath, fstools.defaultMask)
42+
entry.autodrain()
43+
} else {
44+
entry.pipe(fs.createWriteStream(filepath, {'mode': fstools.defaultMask}))
45+
}
46+
}
47+
}).on('close', function () {
48+
process.stdout.write('Application successfully updated\n')
49+
fs.unlinkSync(dir + '/master.zip')
50+
process.exit(0)
51+
})
52+
}).pipe(fs.createWriteStream(localZipFile))
53+
})
4754
}

0 commit comments

Comments
 (0)
Please sign in to comment.