Use .opvn file extension

Suggestions/comments/criticisms are welcome here

piranha

Posts: 6
Joined: Sun Aug 30, 2009 9:10 am

Post by piranha » Fri Jan 18, 2013 8:38 am
Hey,

If I export a VPN-Config the file extension is .conf... Why it isn't standard .ovpn extension?

I only discovered it, because I tried the OpenVPN-App for iOS, which needs config files with the .ovpn extension..

Thanks
Michael

James

User avatar
Posts: 1890
Joined: Thu Sep 04, 2008 9:27 pm

Post by James » Thu Jan 31, 2013 10:47 am
Hi Michael,

Viscosity predates popular use of the .ovpn extension (back when Viscosity was first developed .conf was the way to go). Viscosity's configurations also must store additional Viscosity configurations, bundle in additional scripts, etc., so it would be misleading to indicate that they are simply standard raw OpenVPN config files. We are looking at making an export option designed for the iOS client, however in the meantime here is our recommended method:

1. Select your connection in Viscosity's Preferences window
2. Click on the small cog button near the bottom right and select "Export Connection". Save it to your Desktop.
3. If you are using a Mac, right-click on your saved connection in the Finder and select "Show Package Contents". Under Windows you can simply double-click on the folder.
4. Rename the "config.conf" file to end with ".ovpn" instead (you can give it a different name as well if you wish).
5. Drag all of the files into the OpenVPN Documents section in iTunes (the iOS app doesn't require them all to be a single file).

Cheers,
James
James Bekkema
Viscosity Developer

Web: http://www.sparklabs.com
Support: http://www.sparklabs.com/support
Twitter: http://twitter.com/sparklabs

Brian Bruggeman

Posts: 1
Joined: Thu Jul 06, 2017 4:35 pm

Post by Brian Bruggeman » Thu Jul 06, 2017 4:42 pm
So I had this problem this evening, and I just went ahead and created a gist for it using Python...

https://gist.github.com/brianbruggeman/ ... 1071be5946


Basic steps are:

1. Install click: pip install click
2. Usage:
viscosity-to-openvpn.py <input> <output>

E.g.

a. Export .visc or .visz to desktop
b. python viscosity-to-openvpn.py ~/Desktop/<filename>.vis{c,v}


LICENSE: Public Domain

Code (viscosity-to-openvpn.py):
Code: Select all
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Converts viscosity export files into an open vpn package
Usage: viscosity-to-openvpn.py <input> <output>
"""
import io
import os
import sys
import tarfile

import click

if sys.version.startswith('3'):
    unicode = str


# ----------------------------------------------------------------------
# Exceptions
# ----------------------------------------------------------------------
class ConversionError(Exception):
    """Base conversion error"""
    pass


class NoConnectionName(ConversionError):
    """No connection name was available"""
    pass


class NoCertificateData(ConversionError):
    """No certificate data was found within certificate file"""
    pass


class NoCertificateFile(ConversionError):
    """File was not available within archive"""
    pass

# ----------------------------------------------------------------------
# Command-line Interface
# ----------------------------------------------------------------------
@click.command()
@click.argument('input-path', type=click.Path(exists=True))
@click.argument('output', required=False, type=click.Path(), default=None)
def convert(input_path, output=None):
    '''Converts Viscosity package

    Args:
        input (str): path to folder or file input
        output (str): path to folder output  [default: None]
    '''
    if input_path.endswith('.visc'):
        output = input_path if output is None else output
        if output and not os.path.exists(output):
            output = input_path
        files = [os.path.join(input_path, filename) for filename in os.listdir(input_path)]
        for config_fp in files:
            new_config = []
            if config_fp.endswith('.conf'):
                with io.open(config_fp, encoding='utf-8') as stream:
                    connection_name = extract(stream, new_config, input_path=input_path)

                new_config.insert(0, '# OpenVPN Config for {}'.format(connection_name))
                new_config = '\n'.join(new_config) + '\n'
                output_filepath = os.path.join(output, '{}.ovpn'.format(connection_name))
                with io.open(output_filepath, 'w', encoding='utf-8') as out:
                    out.write(unicode(new_config))

                print('Wrote: {}'.format(output_filepath))

    elif input_path.endswith('.visz'):
        if output is None:
            output = os.path.dirname(input_path)

        data = {}
        with tarfile.open(input_path) as zipped:
            for filepath, fileinfo in zip(zipped.getnames(), zipped.getmembers()):
                if not fileinfo.isfile():
                    continue
                filename = filepath.split(os.path.sep)[-1]
                data[filename] = zipped.extractfile(filepath).read()

        for key in data:
            if not key.endswith('.conf') or key.startswith('.'):
                continue

            import pdb; pdb.set_trace()
            new_config = []
            lines = data[key].split('\n')
            connection_name = extract(lines, new_config, file_data=data)

            new_config.insert(0, '# OpenVPN Config for {}'.format(connection_name))
            new_config = '\n'.join(new_config) + '\n'
            output_filepath = os.path.join(output, '{}.ovpn'.format(connection_name))
            with io.open(output_filepath, 'w', encoding='utf-8') as out:
                out.write(unicode(new_config))

            print('Wrote: {}'.format(output_filepath))


# ----------------------------------------------------------------------
# CLI Support
# ----------------------------------------------------------------------
def extract(data, new_config, input_path=None, file_data={}):
    certificate_files = ['ca', 'cert', 'key', 'tls-auth']
    connection_name = ''
    for line in data:
        line = line.rstrip()

        if not line.strip():
            continue

        # This was an invalid configuration, for some reason
        elif line == 'compress lzo':
            continue

        elif line.startswith('#'):
            if line.startswith('#viscosity name'):
                connection_name = line.split('#viscosity name ', 1)[-1]
                connection_name = connection_name.strip()
            continue

        try:
            key, value = line.split(' ', 1)
            value = value.strip()
        except ValueError:
            key, value = line, ''

        if key in certificate_files:
            if key == 'tls-auth':
                value, direction = value.split(' ', 1)
                if direction:
                    new_config.append('key-direction {}'.format(direction))

            if input_path:
                cert_filepath = os.path.join(input_path, value)
                with io.open(cert_filepath, encoding='utf-8') as cf:
                    certificate = cf.read()
            else:
                if value not in file_data:
                    raise NoCertificateFile('Could not find certificate file in archive')
                certificate = file_data.get(value)

            if not certificate:
                raise NoCertificateData('Could not find certificate data')

            new_config.append('<%s>' % key)
            new_config.append(certificate)
            new_config.append('</%s>' % key)
            continue

        new_config.append(line)

    if not connection_name.strip():
        raise NoConnectionName('Could not find connection name in file.  Aborting')

    return connection_name


if __name__ == '__main__':
    convert()
3 posts Page 1 of 1