Commit aa42fda5 authored by Johannes Zellner's avatar Johannes Zellner

Add initial settings ui and save

parent 589e159a
......@@ -20,5 +20,9 @@ fi
# Generate random management token for admin api
dd if=/dev/urandom bs=256 count=1 | base64 > .dev/run/admin-token
if [ ! -f .dev/data/openvpn.conf ]; then
cp openvpn.conf.template .dev/data/openvpn.conf
fi
echo "Starting server"
exec ./server.js
......@@ -20,7 +20,7 @@
<header>
<h1><span class="hidden-xs-only">Cloudron OpenVPN</span></h1>
<el-button id="openSettingsButton" v-show="user && user.isAdmin" @click="view = 'settings'" icon="el-icon-setting">Settings</el-button>
<el-button id="openSettingsButton" v-show="user && user.isAdmin" @click="openSettings()" icon="el-icon-setting">Settings</el-button>
<el-button id="logoutButton" v-show="user" @click="logout()">Logout</el-button>
</header>
......@@ -40,7 +40,21 @@
</el-form>
</div>
<div class="container" v-show="view === 'settings'">
Settings
<h2>Settings</h2>
<el-form ref="form" :model="settings" label-position="left">
<el-form-item label="Network Address">
<el-input v-model="settings.networkAddress"></el-input>
</el-form-item>
<el-form-item label="DNS Server">
<el-input v-model="settings.dnsServer"></el-input>
</el-form-item>
<el-form-item label="Allow Client-to-Client connection">
<el-switch v-model="settings.allowICC"></el-switch>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSettingsSave()">Save</el-button>
</el-form-item>
</el-form>
</div>
<div class="container" v-show="view === 'devices'">
<div class="toolbar">
......
......@@ -17,7 +17,8 @@
entries: [],
user: null,
loginForm: {username: '', password: ''},
connectedClients: {}
connectedClients: {},
settings: {}
},
computed: {
connectedClientCount () {
......@@ -193,6 +194,38 @@
},
toggleRowExpansion (row, event, column) {
this.$refs.deviceTable.toggleRowExpansion(row)
},
refreshSettings () {
superagent.get('/api/settings')
.end((error, result) => {
this.busy = false
if (result && result.statusCode === 401) {
this.view = VIEWS.LOGIN
this.$nextTick(() => this.$refs.usernameInput.focus())
return this.user = null
}
if (error) return console.error(error)
this.settings = result.body.settings
})
},
onSettingsSave () {
superagent.post('/api/settings', { settings: this.settings })
.end((error, result) => {
if (result && result.statusCode === 401) {
this.$nextTick(() => this.$refs.passwordInput.focus())
return
}
if (error) return console.error(error)
this.refreshSettings()
})
},
openSettings () {
this.view = VIEWS.SETTINGS
this.refreshSettings()
}
}
})
......
......@@ -23,8 +23,12 @@ const jsonParser = bodyParser.json({strict: true})
const baseDir = process.env.CLOUDRON ? '/app/data' : path.join(__dirname, '.dev/data')
// config is for app configs, settings is for openvpn settings
const CONFIG_FILE_PATH = path.join(baseDir, 'config.ini')
console.log(`Using config file at ${CONFIG_FILE_PATH}`)
const OPENVPN_SETTINGS_FILE_PATH = path.join(baseDir, 'openvpn.conf')
console.log(`Using app config file at ${CONFIG_FILE_PATH}`)
console.log(`Using OpenVPN settings file at ${OPENVPN_SETTINGS_FILE_PATH}`)
function reloadConfig() {
let config = {}
......@@ -43,6 +47,71 @@ function reloadConfig() {
let config = reloadConfig()
// This only fetches the settings supported by the UI
function getOpenVPNSetting() {
let settings = {}
// this crashes the app intentionally to restart it and let it create a default
let tmp = ''
try {
tmp = fs.readFileSync(OPENVPN_SETTINGS_FILE_PATH, 'utf-8')
} catch (e) {
console.error(e)
process.exit(1)
}
// ignore comments and empty lines
tmp = tmp.split('\n').map((l) => { return l.trim() })
tmp = tmp.filter((l) => { return l && l[0] !== '#' })
function findItem(prefix) {
let idx = tmp.findIndex((l) => { return l.indexOf(prefix) === 0 })
if (idx === -1) return null
return tmp[idx].slice(prefix.length).trim().replace(/["]+$/g, '')
}
settings.networkAddress = findItem('server')
settings.dnsServer = findItem('push "dhcp-option DNS')
settings.allowICC = findItem('client-to-client') !== null
return settings
}
// This only fetches the settings supported by the UI
function setOpenVPNSetting(settings) {
// this crashes the app intentionally to restart it and let it create a default
let tmp = ''
try {
tmp = fs.readFileSync(OPENVPN_SETTINGS_FILE_PATH, 'utf-8')
} catch (e) {
console.error(e)
process.exit(1)
}
tmp = tmp.split('\n')
// allowICC
let idx = tmp.findIndex((l) => { return l.indexOf('client-to-client') !== -1 })
let value = (settings.allowICC ? '' : '# ') + 'client-to-client'
if (idx === -1) tmp.push(value)
else tmp[idx] = value
// networkAddress
idx = tmp.findIndex((l) => { return l.indexOf('server ') !== -1 })
value = `server ${settings.networkAddress}`
if (idx === -1) tmp.push(value)
else tmp[idx] = value
// dnsServer
idx = tmp.findIndex((l) => { return l.indexOf('push "dhcp-option DNS') !== -1 })
value = `push "dhcp-option DNS ${settings.dnsServer}"`
if (idx === -1) tmp.push(value)
else tmp[idx] = value
fs.writeFileSync(OPENVPN_SETTINGS_FILE_PATH, tmp.join('\n'), 'utf-8')
}
const isAuthenticated = (req, res, next) => (req.session && req.session.user) ? next() : res.status(401).send({})
app.use('/api/healthcheck', (req, res) => openvpn.isRunning()
......@@ -94,6 +163,13 @@ router.get('/api/logout', (req, res) => {
router.get('/api/profile', isAuthenticated, (req, res, next) => {
next(new HttpSuccess(200, {user: req.session.user}))
})
router.get('/api/settings', isAuthenticated, (req, res, next) => {
next(new HttpSuccess(200, { settings: getOpenVPNSetting() }))
})
router.post('/api/settings', isAuthenticated, jsonParser, (req, res, next) => {
setOpenVPNSetting(req.body.settings)
next(new HttpSuccess(201, {}))
})
router.post('/api/onConnect/', urlEncodedParser, openvpn.onClientConnect)
router.post('/api/onDisconnect/', urlEncodedParser, openvpn.onClientDisconnect)
router.post('/api/onLearnAddress/', urlEncodedParser, openvpn.onLearnAddress)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment