diff --git a/index.html b/index.html
index d79cb3f..0606be4 100644
--- a/index.html
+++ b/index.html
@@ -1,4 +1,4 @@
-
+
@@ -17,7 +17,7 @@
diff --git a/js/converter.js b/js/converter.js
index 5b8d75a..95e27be 100644
--- a/js/converter.js
+++ b/js/converter.js
@@ -8,25 +8,72 @@ const oncBasics = {
'NetworkConfigurations': []
}
-export function convert(name, ovpn) {
+export function convert(name, ovpn, keys) {
if (!ovpn.client) {
console.warn('Is this a server file?')
}
-
- // Check parameters
let params = {}
+
+ // Add certificates
+ let certs = []
+ let [cas, caGuids] = createCerts(keys, ovpn['ca'], 'Authority')
+ params['ServerCARefs'] = caGuids
+ certs = certs.concat(cas)
+ let [clientCerts, clientCertGuids] = createCerts(keys, ovpn['cert'], 'Client')
+ if (clientCerts[0]) {
+ params['ClientCertType'] = 'Ref'
+ params['ClientCertRef'] = clientCertGuids[0]
+ certs.push(clientCerts[0])
+ } else {
+ params['ClientCertType'] = 'None'
+ }
+
+ // Add parameters
let remote = ovpn.remote.split(' ')
const host = remote[0]
- if (remote[1]) {
- params['Port'] = remote[1]
- }
- if (ovpn.proto) {
- params['Proto'] = ovpn.proto
+ if (remote[1]) params['Port'] = remote[1]
+ if (ovpn['auth-user-pass']) params['UserAuthenticationType'] = 'Password'
+ if (ovpn['comp-lzo'] && ovpn['comp-lzo'] !== 'no') {
+ params['CompLZO'] = 'true'
+ } else {
+ params['CompLZO'] = 'false'
}
+ if (ovpn['persist-key']) params['SaveCredentials'] = true
if (ovpn['tls-auth']) {
- params['TLSAuthContents'] = convertKey(ovpn['tls-auth'])
+ let authKey = ovpn['tls-auth'].split(' ')
+ params['TLSAuthContents'] = convertKey(keys[authKey[0]])
+ if (authKey[1]) params['KeyDirection'] = authKey[1]
}
+ if (ovpn['verify-x509-name']) {
+ params['VerifyX509'] = {
+ 'Name': ovpn['verify-x509-name']
+ }
+ }
+ // set parameters if they exist in the ovpn config
+ let conditionalSet = (ovpnName, oncName, type='str') => {
+ if (ovpn[ovpnName]) {
+ const raw = ovpn[ovpnName]
+ let value
+ switch (type) {
+ case 'int':
+ value = Number(raw)
+ break
+ default:
+ value = raw
+ }
+ params[oncName] = value
+ }
+ }
+ conditionalSet('port', 'Port', 'int')
+ conditionalSet('proto', 'Proto')
+ conditionalSet('key-direction', 'KeyDirection')
+ conditionalSet('remote-cert-tls', 'RemoteCertTLS')
+ conditionalSet('cipher', 'Cipher')
+ conditionalSet('auth', 'Auth')
+ conditionalSet('auth-retry', 'AuthRetry')
+ conditionalSet('reneg-sec', 'RenegSec', 'int')
+ // Put together network configuration
let config = {
'GUID': `{${uuidv4()}}`,
'Name': name,
@@ -37,8 +84,11 @@ export function convert(name, ovpn) {
'OpenVPN': params
}
}
+
+ // Put everything together
let onc = Object.assign({}, oncBasics) // create copy
onc.NetworkConfigurations = [config]
+ onc.Certificates = certs
return onc
}
@@ -52,5 +102,42 @@ function uuidv4() {
}
function convertKey(key) {
- return key.replace(/\n/g, '\n') + '\n'
+ let lines = key.split(/\n/g)
+ let out = ''
+ for (let line of lines) {
+ // filter out empty lines and lines with comments
+ if (!line || line.match(/^\s*[;#]/)) continue
+ out += line + '\n'
+ }
+ return out
+}
+
+function extractCas(str) {
+ let splits = str.replace(/\n/g, '').split('-----BEGIN CERTIFICATE-----')
+ console.log(splits)
+ let cas = []
+ for (const s of splits) {
+ if (s.includes('-----END CERTIFICATE-----')) {
+ cas.push(s.split('-----END CERTIFICATE-----')[0])
+ }
+ }
+ return cas
+}
+
+function createCerts(keys, certName, certType) {
+ let certs = []
+ let certGuids = []
+ if (certName) {
+ let rawCerts = extractCas(keys[certName])
+ for (const cert of rawCerts) {
+ const guid = `{${uuidv4()}}`
+ certGuids.push(guid)
+ certs.push({
+ 'GUID': guid,
+ 'Type': certType,
+ 'X509': cert
+ })
+ }
+ }
+ return [certs, certGuids]
}
diff --git a/js/main.js b/js/main.js
index 55a5133..84deba1 100644
--- a/js/main.js
+++ b/js/main.js
@@ -2,28 +2,40 @@ import {decode} from './parser.js'
import {convert} from './converter.js'
let clickButton = document.getElementById('clickbutton')
-clickButton.addEventListener('click', main, false)
+clickButton.addEventListener('click', handler, false)
-function main() {
+function handler() {
let selectedFile = document.getElementById('inputopenvpn').files[0]
+ let certificates = document.getElementById('inputcertificates').files
let connName = document.getElementById('connname').value
+ let output = document.getElementById('output')
+ main(connName, selectedFile, certificates, output)
+}
+
+async function main(connName, selectedFile, certificateFiles, output) {
if (connName === '') {
alert('Please specify a name for the connection.')
return
}
console.log(selectedFile.size + ' bytes')
- let reader = new FileReader()
- // callback for when reader is done
- reader.onload = (e => {
- let content = e.target.result
- // remove windows-style newlines
- content = content.replace(/\r/g, '')
- let parsed = decode(content)
- console.log(parsed)
- let onc = convert(connName, parsed)
- let output = document.getElementById('output')
- output.value = JSON.stringify(onc, null, 2)
- });
- // start reading
- reader.readAsText(selectedFile)
+ let content = await readFile(selectedFile)
+ let [ovpn, keys] = decode(content)
+ console.log(ovpn)
+ for (const certificateFile of certificateFiles) {
+ keys[certificateFile.name] = await readFile(certificateFile)
+ }
+ let onc = convert(connName, ovpn, keys)
+ output.value = JSON.stringify(onc, null, 2)
+}
+
+function readFile(file) {
+ return new Promise(resolve => {
+ let reader = new FileReader()
+ reader.onload = (e => {
+ // callback and remove windows-style newlines
+ resolve(e.target.result.replace(/\r/g, ''))
+ })
+ // start reading
+ reader.readAsText(file)
+ })
}
diff --git a/js/parser.js b/js/parser.js
index 387328f..ac1b986 100644
--- a/js/parser.js
+++ b/js/parser.js
@@ -1,5 +1,9 @@
+/**
+ * Parse *.ovpn file.
+ */
export function decode (str) {
- let out = {}
+ let ovpn = {}
+ let keys = {}
const re = /^([^ ]+)( (.*))?$/i
const xmlOpen = /^<([^\/].*)>$/i
const xmlClose = /^<\/(.*)>$/i
@@ -20,9 +24,10 @@ export function decode (str) {
if (tag !== xmlTag) {
throw 'bad xml tag'
}
- const key = unsafe(xmlTag)
+ const name = unsafe(xmlTag)
const value = unsafe(xmlContent)
- out[key] = value
+ keys[name] = value
+ ovpn[name] = name
xmlContent = ''
inXml = false
continue
@@ -37,10 +42,10 @@ export function decode (str) {
if (!match) continue
const key = unsafe(match[1])
const value = match[2] ? unsafe((match[3] || '')) : true
- out[key] = value
+ ovpn[key] = value
}
- return out
+ return [ovpn, keys]
}
function isQuoted (val) {