riseup_vpn 0.1.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +21 -12
- data/Rakefile +0 -2
- data/lib/riseup_vpn/api.rb +5 -7
- data/lib/riseup_vpn/errors.rb +7 -0
- data/lib/riseup_vpn/generator.rb +19 -35
- data/lib/riseup_vpn/manager.rb +54 -0
- data/lib/riseup_vpn/nmcli.rb +16 -0
- data/lib/riseup_vpn/utils.rb +25 -0
- data/lib/riseup_vpn/version.rb +2 -2
- data/lib/riseup_vpn.rb +8 -6
- data/sig/riseup_vpn.rbs +1 -1
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b9fb7defcb7a949292d44dc949acfdc4524eb599a21ec1c90f5f1680c8b9d0ff
|
4
|
+
data.tar.gz: dcbb98a3d236a6bf35d3fab3f073549836e98d976a747a4dd134417f6f3ad43e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01bf804c22e6edde11abfd61073f3a9093d33b9463e05f5456aa66f7537e44e19ef37708979499ca8193b05045439acdba5b3a46337ef4edc219053e9603e373
|
7
|
+
data.tar.gz: 219ee6e1de2521e85e94a558e28dda6347b3cb74e288bb293f04a86599975f76e00f4477b1d73493562403971f2e0435ff9fb4bde77404a774a690bd489dbd7f
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [1.1.0] - 2025-04-22
|
4
|
+
|
5
|
+
### New features
|
6
|
+
|
7
|
+
- add ability to import VPN client configs into Network Manager (Linux)
|
8
|
+
|
9
|
+
## [1.0.0] - 2025-04-21
|
10
|
+
|
11
|
+
### Breaking changes
|
12
|
+
|
13
|
+
- Namespace changes: `RiseupVpn` -> `RiseupVPN`, `RiseupVpn::Api` -> `RiseupVPN::API` and `Generator` -> `Manager`
|
14
|
+
- `#write_files` no longer takes an dir path arg
|
15
|
+
- All errors subclass `RiseupVPN::Error`
|
16
|
+
|
17
|
+
### New features
|
18
|
+
|
19
|
+
- upgrade TLS to 1.3, if supported by client
|
20
|
+
|
3
21
|
## [0.1.0] - 2025-04-19
|
4
22
|
|
5
23
|
- Initial release
|
data/README.md
CHANGED
@@ -3,12 +3,12 @@
|
|
3
3
|
|
4
4
|
# RiseupVPN
|
5
5
|
|
6
|
-
A tool to create .ovpn ([OpenVPN](https://openvpn.net)) client config files for use with [RiseupVPN](https://riseup.net/vpn). Such files can be imported using, for example, the Debian [openvpn NetworkManager plugin](https://packages.debian.org/search?keywords=network-manager-openvpn). You will then be able to route your network connection through any of Riseup's 20+ VPN gateways!
|
7
|
-
|
8
|
-
This project was inspired by [this](https://sizeof.cat/project/riseupvpn-to-openvpn) very excellent web tool.
|
6
|
+
A tool to create .ovpn ([OpenVPN](https://openvpn.net)) client config files for use with [RiseupVPN](https://riseup.net/vpn). Such files can be imported using, for example, the Debian [openvpn NetworkManager plugin](https://packages.debian.org/search?keywords=network-manager-openvpn). You will then be able to route your network connection through any of Riseup's 20+ VPN gateways! The screenshot below shows Linux Mint's Network Manager panel applet with an active VPN connection to RiseupVPN's Seattle gateway.
|
9
7
|
|
10
8
|

|
11
9
|
|
10
|
+
This project was inspired by [this](https://sizeof.cat/project/riseupvpn-to-openvpn) very excellent web tool.
|
11
|
+
|
12
12
|
## Installation
|
13
13
|
|
14
14
|
Install the gem and add to the application's Gemfile by executing:
|
@@ -28,27 +28,36 @@ gem install riseup_vpn
|
|
28
28
|
```ruby
|
29
29
|
require 'riseup_vpn'
|
30
30
|
|
31
|
-
|
32
|
-
# => instance_of
|
31
|
+
@manager = RiseupVPN::Manager.new # takes an optional positional arg for the dir path. Default is '~/.config/riseup_vpn'
|
32
|
+
# => instance_of RiseupVPN::Manager
|
33
33
|
|
34
|
-
|
34
|
+
@manager.ovpns
|
35
35
|
# => {"vpn01-sea.riseup.net" => "client\ntls-client\ndev tun\nproto udp\nremote 204.13.164.252 1194 ...
|
36
36
|
|
37
|
-
|
37
|
+
@manager.ovpns.size
|
38
38
|
# => 21
|
39
39
|
|
40
|
-
|
41
|
-
# => {proto: ["udp", "tcp"]}
|
40
|
+
RiseupVPN::Manager::OPTS # returns a list of valid options which maybe passed as an optional hash at initialization.
|
41
|
+
# => {proto: ["udp", "tcp"]} defaults are the first values e.g. 'udp' for :proto
|
42
|
+
# For example; RiseupVPN::Manager.new('/some/path', proto: 'tcp')
|
42
43
|
|
43
|
-
|
44
|
+
@manager.write_files # (over)writes the VPN client config files to the dir path
|
44
45
|
```
|
45
|
-
The last command creates the following files
|
46
|
+
The last command creates (or overwrites) the following files:
|
46
47
|
- an .ovpn file for each VPN gateway
|
47
48
|
- the Certificate Authority cert file (ca.crt)
|
48
49
|
- the client private key file (client.key)
|
49
50
|
- the client cert file (client.crt)
|
50
51
|
|
51
|
-
Note:
|
52
|
+
Note: The last 2 expire after 30 days and therefore need to be updated regularly.
|
53
|
+
|
54
|
+
Also note: OpenVPN requires that cert & key files shared across .ovpn client config files are present in the same directory.
|
55
|
+
|
56
|
+
On Linux, you can do this to make Riseup's VPNs available in Network Manager. It uses `nmcli` under the hood:
|
57
|
+
```Ruby
|
58
|
+
@manager.import_ovpn_configs # writes the files and (re)imports the VPN configs into Network Manager
|
59
|
+
# the client key and cert files are updated too
|
60
|
+
```
|
52
61
|
|
53
62
|
## \_why?
|
54
63
|
|
data/Rakefile
CHANGED
data/lib/riseup_vpn/api.rb
CHANGED
@@ -2,11 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'openssl'
|
4
4
|
|
5
|
-
module
|
5
|
+
module RiseupVPN
|
6
6
|
# parses ca.cert, client cert/key & gateways data from riseup.net API
|
7
|
-
module
|
8
|
-
class ApiError < StandardError; end
|
9
|
-
|
7
|
+
module API
|
10
8
|
PROVIDER = 'https://riseup.net/provider.json' # entry point for API
|
11
9
|
API_URI = 'https://api.black.riseup.net' # 443
|
12
10
|
API_VERSION = '3'
|
@@ -35,15 +33,15 @@ module RiseupVpn
|
|
35
33
|
def get(url)
|
36
34
|
URI(url).read
|
37
35
|
rescue NoMethodError, URI::Error
|
38
|
-
raise
|
36
|
+
raise APIError, "Bad URI: '#{url}'"
|
39
37
|
rescue OpenURI::HTTPError
|
40
|
-
raise
|
38
|
+
raise APIError, "Failed to get url: '#{url}'"
|
41
39
|
end
|
42
40
|
|
43
41
|
def get_json(url)
|
44
42
|
JSON.parse get(url)
|
45
43
|
rescue JSON::ParserError
|
46
|
-
raise
|
44
|
+
raise APIError, "Failed to parse JSON at: '#{url}'"
|
47
45
|
end
|
48
46
|
end
|
49
47
|
end
|
data/lib/riseup_vpn/generator.rb
CHANGED
@@ -1,57 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'openssl'
|
4
3
|
require 'yaml'
|
5
4
|
|
6
5
|
require_relative 'api'
|
6
|
+
require_relative 'utils'
|
7
7
|
|
8
|
-
module
|
9
|
-
#
|
8
|
+
module RiseupVPN
|
9
|
+
# queries API and builds ovpn config files, CA cert and client key & cert
|
10
10
|
class Generator
|
11
|
+
include Utils
|
12
|
+
|
11
13
|
TEMPLATE = YAML.load_file File.join(__dir__, 'template_ovpn.yml')
|
12
14
|
OPTS = { proto: %w[udp tcp] }.freeze # default is 1st value
|
13
|
-
LINE_METHODS = %i[remote verify-x509-name].freeze
|
15
|
+
LINE_METHODS = %i[remote tls-version-min verify-x509-name].freeze
|
14
16
|
|
15
|
-
attr_reader :ovpns
|
17
|
+
attr_reader :ovpns, :ca_crt, :client_key, :client_crt
|
16
18
|
|
17
19
|
def initialize(opts = {})
|
18
20
|
@opts = validate_options opts.transform_keys!(&:to_sym)
|
19
|
-
@server_config = server_config
|
20
21
|
@template = template
|
22
|
+
@server_config = server_config
|
21
23
|
@ovpns = generate_ovpns # hash { gateway_name => string }
|
22
|
-
|
23
|
-
|
24
|
-
def write_files(dir)
|
25
|
-
dir = File.expand_path dir.to_s
|
26
|
-
write_ovpn_files dir
|
27
|
-
write_ca_file dir
|
28
|
-
write_client_key_and_crt_files dir
|
29
|
-
rescue Errno::ENOENT, Errno::EACCES
|
30
|
-
raise ArgumentError, "Dir #{dir} doesn't exist or isn't writable"
|
24
|
+
@ca_crt = API.ca_crt
|
25
|
+
@client_key, @client_crt = API.client_key_and_crt
|
31
26
|
end
|
32
27
|
|
33
28
|
private
|
34
29
|
|
35
|
-
def write_ovpn_files(dir)
|
36
|
-
ovpns.each { |k, v| File.write(File.join(dir, "#{k}.ovpn"), v) }
|
37
|
-
end
|
38
|
-
|
39
|
-
def write_ca_file(dir)
|
40
|
-
File.write File.join(dir, 'ca.crt'), Api.ca_crt.to_s.chomp
|
41
|
-
end
|
42
|
-
|
43
|
-
def write_client_key_and_crt_files(dir)
|
44
|
-
client_key, client_crt = Api.client_key_and_crt
|
45
|
-
File.write File.join(dir, 'client.key'), client_key.to_s.chomp
|
46
|
-
File.write File.join(dir, 'client.crt'), client_crt.to_s.chomp
|
47
|
-
end
|
48
|
-
|
49
30
|
def gateways
|
50
|
-
|
31
|
+
API.eip['gateways']
|
51
32
|
end
|
52
33
|
|
53
34
|
def server_config
|
54
|
-
|
35
|
+
API.eip['openvpn_configuration'].transform_keys(&:to_sym)
|
55
36
|
end
|
56
37
|
|
57
38
|
def validate_options(opts)
|
@@ -69,17 +50,16 @@ module RiseupVpn
|
|
69
50
|
end
|
70
51
|
|
71
52
|
def template
|
72
|
-
return TEMPLATE.except(*%i[up down]) if
|
73
|
-
return TEMPLATE if RiseupVpn.os == 'linux'
|
53
|
+
return TEMPLATE.except(*%i[up down]) if Utils.os == 'darwin'
|
74
54
|
|
75
|
-
|
55
|
+
TEMPLATE # assumed Linux, see Utils::SUPPORTED_PLATFORMS
|
76
56
|
end
|
77
57
|
|
78
58
|
def generate_line(key, val, gateway)
|
79
59
|
return "#{key} #{val}" if val # hard coded key/value in template file
|
80
60
|
return "#{key} #{@opts[key]}" if @opts[key]
|
81
|
-
return server_config_line(key) if @server_config[key]
|
82
61
|
return send(regularize_method_name(key), gateway) if LINE_METHODS.include? key
|
62
|
+
return server_config_line(key) if @server_config[key]
|
83
63
|
|
84
64
|
key # hard coded key only in template file
|
85
65
|
end
|
@@ -98,6 +78,10 @@ module RiseupVpn
|
|
98
78
|
"remote #{gateway['ip_address']} #{@opts[:proto] == 'udp' ? 1194 : 80}" # TODO: check port 80 in json
|
99
79
|
end
|
100
80
|
|
81
|
+
def tls_version_min(_gateway)
|
82
|
+
"tls-version-min #{Utils.tls_version}"
|
83
|
+
end
|
84
|
+
|
101
85
|
def verify_x509_name(gateway)
|
102
86
|
"verify-x509-name #{name(gateway)} name"
|
103
87
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'generator'
|
4
|
+
|
5
|
+
module RiseupVPN
|
6
|
+
# manages config files
|
7
|
+
class Manager
|
8
|
+
DEFAULT_DIR = '~/.config/riseup_vpn'
|
9
|
+
OPTS = Generator::OPTS
|
10
|
+
|
11
|
+
def initialize(dir = DEFAULT_DIR, opts = {})
|
12
|
+
@dir = File.expand_path dir.to_s
|
13
|
+
@generator = Generator.new(opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
def ovpns
|
17
|
+
@generator.ovpns
|
18
|
+
end
|
19
|
+
|
20
|
+
def write_files
|
21
|
+
write_ovpn_files
|
22
|
+
write_ca_crt
|
23
|
+
write_client_key
|
24
|
+
write_client_crt
|
25
|
+
rescue Errno::ENOENT, Errno::EACCES
|
26
|
+
raise ArgumentError, "Dir #{@dir} doesn't exist or isn't writable"
|
27
|
+
end
|
28
|
+
|
29
|
+
def import_ovpn_configs
|
30
|
+
raise NoMethodError, 'nmcli does not appear to be installed' unless Utils.nmcli?
|
31
|
+
|
32
|
+
write_files
|
33
|
+
Dir["#{@dir}/*.ovpn"].each { |f| Nmcli.import_openvpn f }
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def write_ovpn_files
|
39
|
+
@generator.ovpns.each { |k, v| File.write(File.join(@dir, "#{k}.ovpn"), v) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def write_ca_crt
|
43
|
+
File.write File.join(@dir, 'ca.crt'), @generator.ca_crt.to_s.chomp
|
44
|
+
end
|
45
|
+
|
46
|
+
def write_client_key
|
47
|
+
File.write File.join(@dir, 'client.key'), @generator.client_key.to_s.chomp
|
48
|
+
end
|
49
|
+
|
50
|
+
def write_client_crt
|
51
|
+
File.write File.join(@dir, 'client.crt'), @generator.client_crt.to_s.chomp
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'generator'
|
4
|
+
|
5
|
+
module RiseupVPN
|
6
|
+
# in the absence of an nmcli gem..
|
7
|
+
module Nmcli
|
8
|
+
def self.nmcli(command_string)
|
9
|
+
`nmcli #{command_string}`
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.import_openvpn(file)
|
13
|
+
nmcli "con import type openvpn file #{file}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
module RiseupVPN
|
6
|
+
# utilties for internal use
|
7
|
+
module Utils
|
8
|
+
SUPPORTED_PLATFORMS = %w[darwin linux].freeze
|
9
|
+
|
10
|
+
def self.os
|
11
|
+
os = Gem::Platform.local.os
|
12
|
+
return os if SUPPORTED_PLATFORMS.include? os
|
13
|
+
|
14
|
+
raise Error, "Unsupported OS: '#{os}'"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.tls_version
|
18
|
+
"1.#{OpenSSL::VERSION.to_i}".to_f
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.nmcli?
|
22
|
+
!`which nmcli`.empty?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/riseup_vpn/version.rb
CHANGED
data/lib/riseup_vpn.rb
CHANGED
@@ -3,11 +3,13 @@
|
|
3
3
|
require 'json'
|
4
4
|
require 'open-uri'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
require_relative 'riseup_vpn/api'
|
7
|
+
require_relative 'riseup_vpn/errors'
|
8
|
+
require_relative 'riseup_vpn/generator'
|
9
|
+
require_relative 'riseup_vpn/manager'
|
10
|
+
require_relative 'riseup_vpn/nmcli'
|
11
|
+
require_relative 'riseup_vpn/version'
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
+
# namespace
|
14
|
+
module RiseupVPN
|
13
15
|
end
|
data/sig/riseup_vpn.rbs
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: riseup_vpn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MatzFan
|
@@ -23,8 +23,12 @@ files:
|
|
23
23
|
- assets/vpns.png
|
24
24
|
- lib/riseup_vpn.rb
|
25
25
|
- lib/riseup_vpn/api.rb
|
26
|
+
- lib/riseup_vpn/errors.rb
|
26
27
|
- lib/riseup_vpn/generator.rb
|
28
|
+
- lib/riseup_vpn/manager.rb
|
29
|
+
- lib/riseup_vpn/nmcli.rb
|
27
30
|
- lib/riseup_vpn/template_ovpn.yml
|
31
|
+
- lib/riseup_vpn/utils.rb
|
28
32
|
- lib/riseup_vpn/version.rb
|
29
33
|
- sig/riseup_vpn.rbs
|
30
34
|
- tmp/.placeholder
|