Commit f42d8c22 authored by mehdi's avatar mehdi

initial commit

parents
test/*
node_modules/*
data/
.git/*
screenshots
npm-debug.log
node_modules/
data/
.idea
npm-debug.log
[0.1.0]
* Initial version
{
"id": "io.cloudron.openvpn",
"title": "OpenVPN",
"author": "Mehdi Kouhen",
"description": "file://DESCRIPTION.md",
"tagline": "OpenVPN server and simple web interface",
"tags": [
"vpn",
"openvpn",
"network"
],
"version": "0.1.0",
"healthCheckPath": "/api/healthcheck",
"httpPort": 8000,
"manifestVersion": 1,
"website": "https://git.cloudron.io/mehdi/cloudron-openvpn",
"contactEmail": "arantes555@gmail.com",
"icon": "logo.png",
"configurePath": "_admin/",
"addons": {
"ldap": {},
"oauth": {},
"localstorage": {}
},
"memoryLimit": 536870912,
"tcpPorts": {
"VPN_TCP_PORT": {
"title": "VPN_TCP_PORT",
"description": "Port over which OpenVPN server listens",
"defaultValue": 7494
}
},
"mediaLinks": [
"https://s3.amazonaws.com/cloudron-app-screenshots/io.cloudron.surfer/8c87c0db33704755c3ff9a48fd0089d6ae72928d/img01.png",
"https://s3.amazonaws.com/cloudron-app-screenshots/io.cloudron.surfer/8c87c0db33704755c3ff9a48fd0089d6ae72928d/img02.png",
"https://s3.amazonaws.com/cloudron-app-screenshots/io.cloudron.surfer/8c87c0db33704755c3ff9a48fd0089d6ae72928d/img03.png"
],
"changelog": "file://CHANGELOG",
"postInstallMessage": "file://POSTINSTALL.md"
}
# OpenVPN
This is an OpenVPN server, packaged with a very simple key manager
## Usage
The key management interface is available under the `/` location. Each Cloudron-authenticated user can create and download keys for themself.
FROM cloudron/base:0.10.0
MAINTAINER Mehdi Kouhen <arantes555@gmail.com>
ENV PATH /usr/local/node-6.9.5/bin:$PATH
RUN apt-get update -y
RUN apt-get install -y openvpn easy-rsa
RUN mkdir -p /app/code
WORKDIR /app/code
RUN make-cadir /app/code/easyrsa
ADD package.json /app/code/
RUN npm install --production
ADD src /app/code/src
ADD app /app/code/app
ADD start.sh server.js README.md /app/code/
ADD openvpn/writeOpenVPNConfig.js /app/code/
RUN mkdir -p /app/data
## Supervisor
ADD supervisor/ /etc/supervisor/conf.d/
RUN sed -e 's,^logfile=.*$,logfile=/run/supervisord.log,' -i /etc/supervisor/supervisord.conf
EXPOSE 8000
CMD [ "/app/code/start.sh" ]
The MIT License (MIT)
Copyright (c) 2017 Mehdi Kouhen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
To access the key management interface, visit `/`.
# OpenVPN
This is an OpenVPN server, packaged with a very simple key manager
## Installation
[![Install](https://cloudron.io/img/button32.png)](https://cloudron.io/button.html?app=io.cloudron.openvpn)
or using the [Cloudron command line tooling](https://cloudron.io/references/cli.html)
```
cloudron install --appstore-id io.cloudron.openvpn
```
## Building
### Cloudron
The app package can be built using the [Cloudron command line tooling](https://cloudron.io/references/cli.html).
```
git clone https://git.cloudron.io/mehdi/cloudron-openvpn.git
cd cloudron-openvpn
cloudron build
cloudron install
```
## Usage
The key management interface is available under the `/` location. Each Cloudron-authenticated user can create and download keys for themself.
## Testing
The e2e tests are located in the `test/` folder and require [nodejs](http://nodejs.org/). They are creating a fresh build, install the app on your Cloudron, perform tests, backup, restore and test if the files are still ok.
```
cd surfer
npm install
USERNAME=<cloudron username> PASSWORD=<cloudron password> mocha --bail test/test.js
```
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
html, body {
min-height: 100%;
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
body {
padding-bottom: 70px;
}
.wrapper {
display: table;
width: 100%;
height: 100%;
}
.content {
display: table-cell;
width: 100%;
height: 100%;
text-align: center;
vertical-align: middle;
}
pre {
margin: auto;
text-align: left;
width: 400px;
}
[v-cloak] {
display: none;
}
.hand {
cursor: pointer;
}
th {
vertical-align: middle !important;
}
button {
margin-left: 5px;
margin-right: 5px;
}
th button {
margin-top: 5px;
margin-bottom: 5px;
}
.main {
margin-bottom: 40px;
}
.btn-refresh {
font-size: 18px;
}
form {
display: inline-block;
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
<html>
<head>
<title> Cloudron OpenVPN config </title>
<link rel="stylesheet" href="/css/font-awesome.min.css">
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/style.css">
<link href="/img/logo.png" rel="icon" type="image/png">
<script src="/js/jquery-1.12.1.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script src="/js/vue.min.js"></script>
<script src="/js/superagent.js"></script>
</head>
<body>
<div id="app">
<nav class="navbar navbar-default" v-cloak>
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">River</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li><a href="/logout" @click="logout()" id="logoutButton">Logout</a></li>
</ul>
</div>
</div>
</nav>
<!-- TODO: implement DELETE
<div class="modal fade" tabindex="-1" role="dialog" id="modalDelete">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<h5 v-show="deleteData.isFile">Really delete <span style="font-weight: bold;">{{ deleteData.filePath }}</span>?
</h5>
<h5 v-show="deleteData.isDirectory">Really delete directory <span style="font-weight: bold;">{{ deleteData.filePath }}</span>
and all its content?</h5>
</div>
<div class="modal-footer">
<button type="button" id="deleteNoBtn" class="btn btn-default" data-dismiss="modal">No</button>
<button type="button" id="deleteYesBtn" class="btn btn-danger" @click="del(deleteData)">Yes</button>
</div>
</div>
</div>
</div>
-->
<div class="modal fade" tabindex="-1" role="dialog" id="modalcreateKey">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title">New Device Name</h4>
</div>
<div class="modal-body">
<form @submit.prevent="createKey(createKeyData)">
<div class="form-group" :class="{ 'has-error': createKeyError }">
<input type="text" class="form-control" v-model="createKeyData" id="inputKeyName"
placeholder="Name" autofocus="true">
<label class="control-label" for="inputKeyName">{{ createKeyError }}</label>
</div>
<button type="submit" style="display: none;"></button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" @click="createKey(createKeyData)">Create
</button>
</div>
</div>
</div>
</div>
<div class="container" v-show="busy" v-cloak>
<div class="row">
<div class="col-lg-12">
<center>
<i class="fa fa-refresh fa-4x fa-spin"></i>
</center>
</div>
</div>
</div>
<div class="container main" v-show="!busy" v-cloak>
<div class="row">
<div class="col-lg-12" style="text-align: right;">
<button class="btn btn-default btn-sm btn-refresh" @click="refresh()"><i class="fa fa-refresh"></i></button>
<button class="btn btn-default btn-sm" @click="createKeyAsk()">New Device</button>
</div>
<div class="col-lg-12">
<table class="table table-hover table-condensed">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Created</th>
<th style="text-align: right;">Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="entry in entries">
<th><img src="/img/unknown.png" height="48px" width="48px"/></th>
<th><a>{{ entry }}</a></th>
<th><span>--</span></th>
<th style="text-align: right;">
<button class="btn btn-sm" @click.stop="download(entry)" data-toggle="tooltip"
title="Download"><i class="fa fa-download"></i></button>
</th>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script src="/js/app.js"></script>
</body>
</html>
/* global superagent, $, Vue, filesize */
(function () {
'use strict'
Vue.filter('prettyDate', (value) => {
const d = new Date(value)
return d.toDateString()
})
window.app = new Vue({
el: '#app',
data: {
busy: true,
createKeyData: '',
createKeyError: null,
entries: []
},
created () {
$('#modalcreateKey').on('shown.bs.modal', () => $('#inputKeyName').focus())
this.refresh()
},
methods: {
logout () {
window.location.href = '/logout'
},
refresh () {
this.busy = true
superagent.get('/api/list/')
.end((error, result) => {
this.busy = false
if (result && result.statusCode === 401) return this.logout()
if (error) return console.error(error)
this.entries = result.body.entries
Vue.nextTick(() => {
$(() => {
$('[data-toggle="tooltip"]').tooltip()
})
})
})
},
download (entry) {
window.location.href = '/api/key/' + entry
},
/*
delAsk (entry) {
$('#modalDelete').modal('show')
this.deleteData = entry
},
del (entry) {
this.busy = true
superagent.del('/api/keys/' + entry)
.query({
recursive: true
})
.end((error, result) => {
this.busy = false
if (result && result.statusCode === 401) return this.logout()
if (result && result.statusCode !== 200) return console.error('Error deleting file: ', result.statusCode)
if (error) return console.error(error)
this.refresh()
$('#modalDelete').modal('hide')
})
},
*/
createKeyAsk () {
$('#modalcreateKey').modal('show')
this.createKeyData = ''
this.createKeyError = null
},
createKey (name) { // TODO: validate name
this.busy = true
this.createKeyError = null
superagent.put('/api/key/' + this.createKeyData)
.end((error, result) => {
this.busy = false
if (result && result.statusCode === 401) return this.logout()
if (result && result.statusCode === 409) {
this.createKeyError = 'Invalid device name'
return
}
if (result && result.statusCode !== 201) return console.error('Error creating directory: ', result.statusCode)
if (error) return console.error(error)
this.createKeyData = ''
this.refresh()
$('#modalcreateKey').modal('hide')
})
}
}
})
})()
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
logo.png

29.7 KB

#!/usr/bin/env node
'use strict'
const baseDir = '/app/data/keys/'
const VPN_TCP_PORT = process.env.VPN_TCP_PORT || 12345
console.log(`
# Server TCP/${VPN_TCP_PORT}
mode server
proto tcp
port ${VPN_TCP_PORT}
dev tun
# Keys and certificats
ca ${baseDir}ca.crt
cert ${baseDir}cloudron.crt
key ${baseDir}cloudron.key
dh ${baseDir}dh2048.pem
tls-auth ${baseDir}ta.key 0
cipher AES-256-CBC
# Network
server 10.8.0.0 255.255.255.0
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 8.8.4.4"
push "dhcp-option DNS 8.8.8.8"
client-to-client
keepalive 10 120
# Security
user nobody
group nogroup
persist-key
persist-tun
# Log
verb 3
mute 20
status /run/openvpn-status.log
log-append /run/openvpn.log
`)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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