Compare commits
169 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9a9319cb4 | ||
|
|
77e4317135 | ||
|
|
b10d97e53a | ||
|
|
648a4c04d7 | ||
|
|
3ca674dca7 | ||
|
|
fa97fd496e | ||
|
|
c76a7ee8da | ||
|
|
80f6b78332 | ||
|
|
8dc54a7c44 | ||
|
|
8f080c537b | ||
|
|
427cf86f44 | ||
|
|
2d244c08e7 | ||
|
|
82c0f523aa | ||
|
|
c07a0b0ada | ||
|
|
e4c306c0ee | ||
|
|
6ffb94f819 | ||
|
|
142238e8b7 | ||
|
|
678e23c7d6 | ||
|
|
0abcebe1d8 | ||
|
|
f398af1169 | ||
|
|
afbea415e3 | ||
|
|
225bd5d25b | ||
|
|
3651cc6161 | ||
|
|
dc674014ff | ||
|
|
0e0e03949d | ||
|
|
f5bf5c236a | ||
|
|
94480ecabb | ||
|
|
31ef9b1d45 | ||
|
|
bf76132fd4 | ||
|
|
8cc2983318 | ||
|
|
caeca18ed7 | ||
|
|
50febb41ff | ||
|
|
79293e067c | ||
|
|
f45be80591 | ||
|
|
d405ba8dca | ||
|
|
ca975b1c01 | ||
|
|
e0e3ca3832 | ||
|
|
e7c952cbf7 | ||
|
|
85ad2dd39a | ||
|
|
0c4f0ec17b | ||
|
|
5ad4136955 | ||
|
|
a432de95a9 | ||
|
|
1d25a0e18c | ||
|
|
29fd95685f | ||
|
|
62a6016882 | ||
|
|
18a4a79763 | ||
|
|
56ea722f93 | ||
|
|
d2ab974933 | ||
|
|
37d7a8b5fe | ||
|
|
e4dcadd825 | ||
|
|
fee99e9fe3 | ||
|
|
8ac4826126 | ||
|
|
7deb12e06d | ||
|
|
d6e218141b | ||
|
|
f44121b044 | ||
|
|
5d8d92462d | ||
|
|
985cf7b7dd | ||
|
|
dcbc10fd57 | ||
|
|
79f243e98d | ||
|
|
cf95692b93 | ||
|
|
d8e008606f | ||
|
|
3cd26a9f61 | ||
|
|
5d74320ee7 | ||
|
|
f9aadeef1c | ||
|
|
625de1c834 | ||
|
|
1c0a3ed1a4 | ||
|
|
03ba9169f4 | ||
|
|
c22e0e9db7 | ||
|
|
6bcbaf085d | ||
|
|
9a1d9c5d74 | ||
|
|
59a3a072e0 | ||
|
|
9f001bbc06 | ||
|
|
b8356b60a6 | ||
|
|
e2e218c74b | ||
|
|
3bf23cbae5 | ||
|
|
da562d8206 | ||
|
|
81bf83db13 | ||
|
|
7a25dcd130 | ||
|
|
877c7e1a9f | ||
|
|
77b2512745 | ||
|
|
749b73ef15 | ||
|
|
e499eca12c | ||
|
|
80f25c34e5 | ||
|
|
61677fbce2 | ||
|
|
dc6171185e | ||
|
|
f7e4331e93 | ||
|
|
1340511b64 | ||
|
|
c3078f84e8 | ||
|
|
9f65157a0d | ||
|
|
89166cdabf | ||
|
|
b872973e8b | ||
|
|
2000e72357 | ||
|
|
836e53642d | ||
|
|
af3f882bb8 | ||
|
|
2ab05b9350 | ||
|
|
1022eb8a6e | ||
|
|
15fe62de32 | ||
|
|
83d87f83f9 | ||
|
|
76a0c1f6c4 | ||
|
|
a1588302a7 | ||
|
|
91ce790b6b | ||
|
|
5d3982c2d2 | ||
|
|
2cf7f7b268 | ||
|
|
8645d978ba | ||
|
|
cc18b158f4 | ||
|
|
0730b6db6e | ||
|
|
3d2a360401 | ||
|
|
0c60dab384 | ||
|
|
f5f0ad7f28 | ||
|
|
f807f756eb | ||
|
|
11af6c10f1 | ||
|
|
40342619e7 | ||
|
|
19bf62c21f | ||
|
|
2ea00d149f | ||
|
|
cc677bde93 | ||
|
|
6627cda96c | ||
|
|
cade2732b0 | ||
|
|
541a4a3271 | ||
|
|
0eccd068e5 | ||
|
|
87f4b9e422 | ||
|
|
bcaf2e42fd | ||
|
|
d39201f9b3 | ||
|
|
8ac2a816c3 | ||
|
|
344f1bf9ee | ||
|
|
f0a006fc43 | ||
|
|
145da0b21d | ||
|
|
094de89a3e | ||
|
|
65ace12def | ||
|
|
9afe455635 | ||
|
|
45ce422a89 | ||
|
|
4a0738cd49 | ||
|
|
6b6caa435f | ||
|
|
f9cb71027c | ||
|
|
82ac568ee3 | ||
|
|
61afdce788 | ||
|
|
119cac5a67 | ||
|
|
c6fedd9214 | ||
|
|
da525e039d | ||
|
|
29d92fd307 | ||
|
|
3863cc439e | ||
|
|
b1cfc03fc5 | ||
|
|
f706071048 | ||
|
|
501ae2741b | ||
|
|
5b75635386 | ||
|
|
2901db3cf3 | ||
|
|
6c2a3e36b5 | ||
|
|
8b125e6e95 | ||
|
|
e1cc14e055 | ||
|
|
d6659552df | ||
|
|
67001fa958 | ||
|
|
ffeeae91ab | ||
|
|
04fad1b781 | ||
|
|
dcaf952986 | ||
|
|
ca3b9e892d | ||
|
|
9f12ffc069 | ||
|
|
0d6800a515 | ||
|
|
b3d8b78205 | ||
|
|
ee82a85543 | ||
|
|
7907146aaf | ||
|
|
1a677ce4f7 | ||
|
|
f1a6594474 | ||
|
|
f1a82d9d9c | ||
|
|
8b52af0d03 | ||
|
|
dbf5c569ea | ||
|
|
06a2d79cb4 | ||
|
|
eb6238ee52 | ||
|
|
f41fec57ed | ||
|
|
c348343b22 | ||
|
|
b69dcb62e3 |
@@ -8,7 +8,7 @@
|
||||
"vscode"
|
||||
],
|
||||
"shutdownAction": "stopCompose",
|
||||
"postCreateCommand": "source ~/.windows.sh && go mod download && go mod tidy",
|
||||
"postCreateCommand": "~/.windows.sh && go mod download && go mod tidy",
|
||||
"workspaceFolder": "/workspace",
|
||||
"extensions": [
|
||||
"golang.go",
|
||||
|
||||
49
.github/ISSUE_TEMPLATE/bug.md
vendored
49
.github/ISSUE_TEMPLATE/bug.md
vendored
@@ -1,49 +0,0 @@
|
||||
---
|
||||
name: Bug
|
||||
about: Report a bug
|
||||
title: 'Bug: FILL THIS TEXT!'
|
||||
labels: ":bug: bug"
|
||||
assignees: qdm12
|
||||
|
||||
---
|
||||
|
||||
<!---
|
||||
⚠️ Answer the following or I'll insta-close your issue
|
||||
-->
|
||||
|
||||
**Is this urgent?**: No
|
||||
|
||||
**Host OS** (approximate answer is fine too): Ubuntu 18
|
||||
|
||||
<!---
|
||||
🚧 If this is about the Unraid template see https://github.com/qdm12/gluetun/discussions/550
|
||||
-->
|
||||
|
||||
**CPU arch** or **device name**: amd64
|
||||
|
||||
**What VPN provider are you using**:
|
||||
|
||||
**What are you using to run your container?**: Docker Compose
|
||||
|
||||
**What is the version of the program** (See the line at the top of your logs)
|
||||
|
||||
```
|
||||
Running version latest built on 2020-03-13T01:30:06Z (commit d0f678c)
|
||||
```
|
||||
|
||||
**What's the problem** 🤔
|
||||
|
||||
That feature doesn't work
|
||||
|
||||
**Share your logs... (careful to remove in example tokens)**
|
||||
|
||||
```log
|
||||
|
||||
PASTE YOUR LOGS
|
||||
IN THERE
|
||||
|
||||
```
|
||||
|
||||
<!---
|
||||
💡 You can highlight your code with https://docs.github.com/en/github/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlight
|
||||
-->
|
||||
107
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
107
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
name: Bug
|
||||
description: Report a bug
|
||||
title: "Bug: "
|
||||
labels: [":bug: bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
- type: dropdown
|
||||
id: urgent
|
||||
attributes:
|
||||
label: Is this urgent?
|
||||
description: |
|
||||
Is this a critical bug, or do you need this fixed urgently?
|
||||
If this is urgent, note you can use one of the [image tags available](https://github.com/qdm12/gluetun/wiki/Docker-image-tags) if that can help.
|
||||
options:
|
||||
- "No"
|
||||
- "Yes"
|
||||
- type: input
|
||||
id: host-os
|
||||
attributes:
|
||||
label: Host OS
|
||||
description: What is your host OS?
|
||||
placeholder: "Debian Buster"
|
||||
- type: dropdown
|
||||
id: cpu-arch
|
||||
attributes:
|
||||
label: CPU arch
|
||||
description: You can find it on Linux with `uname -m`.
|
||||
options:
|
||||
- x86_64
|
||||
- aarch64
|
||||
- armv7l
|
||||
- "386"
|
||||
- s390x
|
||||
- ppc64le
|
||||
- type: dropdown
|
||||
id: vpn-service-provider
|
||||
attributes:
|
||||
label: VPN service provider
|
||||
options:
|
||||
- Custom
|
||||
- Cyberghost
|
||||
- ExpressVPN
|
||||
- FastestVPN
|
||||
- HideMyAss
|
||||
- IPVanish
|
||||
- IVPN
|
||||
- Mullvad
|
||||
- NordVPN
|
||||
- Privado
|
||||
- Private Internet Access
|
||||
- PrivateVPN
|
||||
- ProtonVPN
|
||||
- PureVPN
|
||||
- Surfshark
|
||||
- TorGuard
|
||||
- VPNUnlimited
|
||||
- VyprVPN
|
||||
- WeVPN
|
||||
- Windscribe
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: docker
|
||||
attributes:
|
||||
label: What are you using to run the container
|
||||
options:
|
||||
- docker run
|
||||
- docker-compose
|
||||
- Portainer
|
||||
- Kubernetes
|
||||
- Podman
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: What is the version of Gluetun
|
||||
description: |
|
||||
Copy paste the version line at the top of your logs.
|
||||
It should be in the form `Running version latest built on 2020-03-13T01:30:06Z (commit d0f678c)`.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: "What's the problem 🤔"
|
||||
placeholder: "That feature does not work..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Share your logs
|
||||
description: No sensitive information is logged out except when running with `LOG_LEVEL=debug`.
|
||||
render: log
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: config
|
||||
attributes:
|
||||
label: Share your configuration
|
||||
description: Share your configuration such as `docker-compose.yml`. Ensure to remove credentials.
|
||||
render: yml
|
||||
7
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
7
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
contact_links:
|
||||
- name: Configuration help?
|
||||
url: https://github.com/qdm12/gluetun/discussions/new
|
||||
about: Please create a Github discussion.
|
||||
- name: Unraid template issue
|
||||
url: https://github.com/qdm12/gluetun/discussions/550
|
||||
about: Please read the relevant Github discussion.
|
||||
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,17 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest a feature to add to this project
|
||||
title: 'Feature request: FILL THIS TEXT!'
|
||||
labels: ":bulb: feature request"
|
||||
assignees: qdm12
|
||||
|
||||
---
|
||||
|
||||
**What's the feature?** 🧐
|
||||
|
||||
- Support this new feature because that and that
|
||||
|
||||
**Optional extra information** 🚀
|
||||
|
||||
- I tried `docker run something` and it doesn't work
|
||||
- That [url](https://github.com/qdm12/gluetun) is interesting
|
||||
19
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
19
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: Feature request
|
||||
description: Suggest a feature to add to Gluetun
|
||||
title: "Feature request: "
|
||||
labels: [":bulb: feature request"]
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: "What's the feature 🧐"
|
||||
placeholder: "Make the tunnel resistant to earth quakes"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: extra
|
||||
attributes:
|
||||
label: "Extra information and references"
|
||||
placeholder: |
|
||||
- I tried `docker run something` and it doesn't work
|
||||
- That [url](https://github.com/qdm12/gluetun) is interesting
|
||||
67
.github/ISSUE_TEMPLATE/help.md
vendored
67
.github/ISSUE_TEMPLATE/help.md
vendored
@@ -1,67 +0,0 @@
|
||||
---
|
||||
name: Help
|
||||
about: Ask for help
|
||||
title: 'Help: FILL THIS TEXT!'
|
||||
labels: ":pray: help wanted"
|
||||
assignees:
|
||||
|
||||
---
|
||||
|
||||
<!---
|
||||
⚠️ If this about a Docker configuration problem or another service:
|
||||
Start a discussion at https://github.com/qdm12/gluetun/discussions/new
|
||||
OR I WILL INSTA-CLOSE YOUR ISSUE.
|
||||
-->
|
||||
|
||||
<!---
|
||||
⚠️ Answer the following or I'll insta-close your issue
|
||||
-->
|
||||
|
||||
**Is this urgent?**: No
|
||||
|
||||
**Host OS** (approximate answer is fine too): Ubuntu 18
|
||||
|
||||
**CPU arch** or **device name**: amd64
|
||||
|
||||
**What VPN provider are you using**:
|
||||
|
||||
**What is the version of the program** (See the line at the top of your logs)
|
||||
|
||||
```
|
||||
Running version latest built on 2020-03-13T01:30:06Z (commit d0f678c)
|
||||
```
|
||||
|
||||
**What's the problem** 🤔
|
||||
|
||||
That feature doesn't work
|
||||
|
||||
**Share your logs... (careful to remove in example tokens)**
|
||||
|
||||
```log
|
||||
|
||||
PASTE YOUR LOGS
|
||||
IN THERE
|
||||
|
||||
```
|
||||
|
||||
**What are you using to run your container?**: Docker Compose
|
||||
|
||||
<!---
|
||||
💡 You can highlight your code with https://docs.github.com/en/github/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlight
|
||||
-->
|
||||
|
||||
Please also share your configuration file:
|
||||
|
||||
```yml
|
||||
your .yml
|
||||
content
|
||||
in here
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
# your docker
|
||||
# run command
|
||||
# in here
|
||||
```
|
||||
18
.github/ISSUE_TEMPLATE/wiki issue.yml
vendored
Normal file
18
.github/ISSUE_TEMPLATE/wiki issue.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Wiki issue
|
||||
description: Report a Wiki issue
|
||||
title: "Wiki issue: "
|
||||
labels: ["📄 Wiki issue"]
|
||||
body:
|
||||
- type: input
|
||||
id: url
|
||||
attributes:
|
||||
label: "URL to the Wiki page"
|
||||
placeholder: "https://github.com/qdm12/gluetun/wiki/OpenVPN-options"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: "What's the issue?"
|
||||
validations:
|
||||
required: true
|
||||
17
.github/labels.yml
vendored
17
.github/labels.yml
vendored
@@ -14,6 +14,14 @@
|
||||
color: "795548"
|
||||
description: ""
|
||||
|
||||
# Priority
|
||||
- name: "🚨 Urgent"
|
||||
color: "d5232f"
|
||||
description: ""
|
||||
- name: "💤 Low priority"
|
||||
color: "4285f4"
|
||||
description: ""
|
||||
|
||||
# VPN providers
|
||||
- name: ":cloud: Cyberghost"
|
||||
color: "cfe8d4"
|
||||
@@ -27,6 +35,9 @@
|
||||
- name: ":cloud: IVPN"
|
||||
color: "cfe8d4"
|
||||
description: ""
|
||||
- name: ":cloud: ExpressVPN"
|
||||
color: "cfe8d4"
|
||||
description: ""
|
||||
- name: ":cloud: FastestVPN"
|
||||
color: "cfe8d4"
|
||||
description: ""
|
||||
@@ -36,6 +47,9 @@
|
||||
- name: ":cloud: NordVPN"
|
||||
color: "cfe8d4"
|
||||
description: ""
|
||||
- name: ":cloud: Perfect Privacy"
|
||||
color: "cfe8d4"
|
||||
description: ""
|
||||
- name: ":cloud: PIA"
|
||||
color: "cfe8d4"
|
||||
description: ""
|
||||
@@ -62,6 +76,9 @@
|
||||
- name: ":cloud: Vyprvpn"
|
||||
color: "cfe8d4"
|
||||
description: ""
|
||||
- name: ":cloud: WeVPN"
|
||||
color: "cfe8d4"
|
||||
description: ""
|
||||
- name: ":cloud: Windscribe"
|
||||
color: "cfe8d4"
|
||||
description: ""
|
||||
|
||||
109
.github/workflows/ci.yml
vendored
109
.github/workflows/ci.yml
vendored
@@ -1,6 +1,24 @@
|
||||
name: CI
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- .github/workflows/ci.yml
|
||||
- cmd/**
|
||||
- internal/**
|
||||
- pkg/**
|
||||
- .dockerignore
|
||||
- .golangci.yml
|
||||
- Dockerfile
|
||||
- go.mod
|
||||
- go.sum
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- .github/workflows/ci.yml
|
||||
- cmd/**
|
||||
@@ -14,11 +32,17 @@ on:
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
# Only run if it's a push event or if it's a PR from this repository, and it is not dependabot.
|
||||
if: |
|
||||
github.actor != 'dependabot[bot]' &&
|
||||
(github.event_name == 'push' ||
|
||||
github.event_name == 'release' ||
|
||||
(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository))
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
- uses: actions/checkout@v2.4.0
|
||||
|
||||
- name: Linting
|
||||
run: docker build --target lint .
|
||||
@@ -44,18 +68,23 @@ jobs:
|
||||
- name: Build final image
|
||||
run: docker build -t final-image .
|
||||
|
||||
- name: Image security analysis
|
||||
uses: snyk/actions/docker@master
|
||||
env:
|
||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
with:
|
||||
image: final-image
|
||||
# - name: Image security analysis
|
||||
# uses: snyk/actions/docker@master
|
||||
# env:
|
||||
# SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
# with:
|
||||
# image: final-image
|
||||
|
||||
publish:
|
||||
# Only run if it's a push event or if it's a PR from this repository
|
||||
if: |
|
||||
github.event_name == 'push' ||
|
||||
github.event_name == 'release' ||
|
||||
(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
|
||||
needs: [verify]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
- uses: actions/checkout@v2.4.0
|
||||
|
||||
- uses: docker/setup-qemu-action@v1
|
||||
- uses: docker/setup-buildx-action@v1
|
||||
@@ -65,35 +94,51 @@ jobs:
|
||||
username: qmcgaw
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Set variables
|
||||
id: vars
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
- name: Check for semver tag
|
||||
id: semvercheck
|
||||
run: |
|
||||
BRANCH=${GITHUB_REF#refs/heads/}
|
||||
TAG=${GITHUB_REF#refs/tags/}
|
||||
echo ::set-output name=commit::$(git rev-parse --short HEAD)
|
||||
echo ::set-output name=created::$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
if [ "$TAG" != "$GITHUB_REF" ]; then
|
||||
echo ::set-output name=version::$TAG
|
||||
echo ::set-output name=platforms::linux/amd64,linux/386,linux/arm64,linux/arm/v6,linux/arm/v7,linux/ppc64le
|
||||
elif [ "$BRANCH" = "master" ]; then
|
||||
echo ::set-output name=version::latest
|
||||
echo ::set-output name=platforms::linux/amd64,linux/386,linux/arm64,linux/arm/v6,linux/arm/v7,linux/ppc64le
|
||||
if [[ ${{ github.ref }} =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
MATCH=true
|
||||
else
|
||||
echo ::set-output name=version::$BRANCH
|
||||
echo ::set-output name=platforms::linux/amd64,linux/386,linux/arm64,linux/arm/v6,linux/arm/v7,linux/ppc64le
|
||||
MATCH=false
|
||||
fi
|
||||
if [[ ! ${{ github.ref }} =~ ^refs/tags/v0\. ]]; then
|
||||
MATCH=$MATCH_nonzero
|
||||
fi
|
||||
echo ::set-output name=match::$MATCH
|
||||
|
||||
# extract metadata (tags, labels) for Docker
|
||||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
with:
|
||||
flavor: |
|
||||
latest=${{ github.ref == 'refs/heads/master' }}
|
||||
images: |
|
||||
qmcgaw/gluetun
|
||||
qmcgaw/private-internet-access
|
||||
tags: |
|
||||
type=ref,event=branch,enable=${{ github.ref != 'refs/heads/master' }}
|
||||
type=ref,event=pr
|
||||
type=ref,event=tag,enable=${{ !startsWith(steps.semvercheck.outputs.match, 'true') }}
|
||||
type=semver,pattern=v{{major}}.{{minor}}.{{patch}},enable=${{ startsWith(steps.semvercheck.outputs.match, 'true') }}
|
||||
type=semver,pattern=v{{major}}.{{minor}},enable=${{ startsWith(steps.semvercheck.outputs.match, 'true') }}
|
||||
type=semver,pattern=v{{major}},enable=${{ startsWith(steps.semvercheck.outputs.match, 'true_nonzero') }}
|
||||
type=raw,value=latest,enable=${{ !startsWith(steps.semvercheck.outputs.match, 'true') }}
|
||||
|
||||
- name: Short commit
|
||||
id: shortcommit
|
||||
run: echo "::set-output name=value::$(git rev-parse --short HEAD)"
|
||||
|
||||
- name: Build and push final image
|
||||
uses: docker/build-push-action@v2.6.1
|
||||
uses: docker/build-push-action@v2.7.0
|
||||
with:
|
||||
platforms: ${{ steps.vars.outputs.platforms }}
|
||||
platforms: linux/amd64,linux/386,linux/arm64,linux/arm/v6,linux/arm/v7,linux/ppc64le
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
CREATED=${{ steps.vars.outputs.created }}
|
||||
COMMIT=${{ steps.vars.outputs.commit }}
|
||||
VERSION=${{ steps.vars.outputs.version }}
|
||||
tags: |
|
||||
qmcgaw/gluetun:${{ steps.vars.outputs.version }}
|
||||
qmcgaw/private-internet-access:${{ steps.vars.outputs.version }}
|
||||
CREATED=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
|
||||
COMMIT=${{ steps.shortcommit.outputs.value }}
|
||||
VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
push: true
|
||||
|
||||
37
.github/workflows/dependabot.yml
vendored
Normal file
37
.github/workflows/dependabot.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Dependabot
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- .github/workflows/dependabot.yml
|
||||
- cmd/**
|
||||
- internal/**
|
||||
- pkg/**
|
||||
- .dockerignore
|
||||
- .golangci.yml
|
||||
- Dockerfile
|
||||
- go.mod
|
||||
- go.sum
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
if: ${{ github.actor == 'dependabot[bot]' }}
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
steps:
|
||||
- uses: actions/checkout@v2.4.0
|
||||
|
||||
- name: Build test image
|
||||
run: docker build --target test -t test-container .
|
||||
|
||||
- name: Run tests in test container
|
||||
run: |
|
||||
touch coverage.txt
|
||||
docker run --rm \
|
||||
-v "$(pwd)/coverage.txt:/tmp/gobuild/coverage.txt" \
|
||||
test-container
|
||||
|
||||
- name: Build final image
|
||||
run: docker build -t final-image .
|
||||
2
.github/workflows/dockerhub-description.yml
vendored
2
.github/workflows/dockerhub-description.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2.3.4
|
||||
uses: actions/checkout@v2.4.0
|
||||
- name: Docker Hub Description
|
||||
uses: peter-evans/dockerhub-description@v2
|
||||
with:
|
||||
|
||||
40
.github/workflows/fork.yml
vendored
Normal file
40
.github/workflows/fork.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Fork
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- .github/workflows/fork.yml
|
||||
- cmd/**
|
||||
- internal/**
|
||||
- pkg/**
|
||||
- .dockerignore
|
||||
- .golangci.yml
|
||||
- Dockerfile
|
||||
- go.mod
|
||||
- go.sum
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
if: github.event.pull_request.head.repo.full_name != github.repository && github.actor != 'dependabot[bot]'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
steps:
|
||||
- uses: actions/checkout@v2.4.0
|
||||
|
||||
- name: Linting
|
||||
run: docker build --target lint .
|
||||
|
||||
- name: Build test image
|
||||
run: docker build --target test -t test-container .
|
||||
|
||||
- name: Run tests in test container
|
||||
run: |
|
||||
touch coverage.txt
|
||||
docker run --rm \
|
||||
-v "$(pwd)/coverage.txt:/tmp/gobuild/coverage.txt" \
|
||||
test-container
|
||||
|
||||
- name: Build final image
|
||||
run: docker build -t final-image .
|
||||
2
.github/workflows/labels.yml
vendored
2
.github/workflows/labels.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
labeler:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
- uses: actions/checkout@v2.4.0
|
||||
- uses: crazy-max/ghaction-github-labeler@v3
|
||||
with:
|
||||
yaml-file: .github/labels.yml
|
||||
|
||||
2
.github/workflows/misspell.yml
vendored
2
.github/workflows/misspell.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
misspell:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
- uses: actions/checkout@v2.4.0
|
||||
- uses: reviewdog/action-misspell@v1
|
||||
with:
|
||||
locale: "US"
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
linters-settings:
|
||||
maligned:
|
||||
suggest-new: true
|
||||
misspell:
|
||||
locale: US
|
||||
|
||||
@@ -30,16 +28,22 @@ issues:
|
||||
linters:
|
||||
- gomnd
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
# - cyclop
|
||||
# - errorlint
|
||||
# - ireturn
|
||||
# - varnamelen
|
||||
# - wrapcheck
|
||||
- asciicheck
|
||||
- bidichk
|
||||
- bodyclose
|
||||
- deadcode
|
||||
- dogsled
|
||||
- dupl
|
||||
- errcheck
|
||||
- durationcheck
|
||||
- errname
|
||||
- exhaustive
|
||||
- exportloopref
|
||||
- forcetypeassert
|
||||
- gci
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
@@ -52,33 +56,33 @@ linters:
|
||||
- goheader
|
||||
- goimports
|
||||
- gomnd
|
||||
- gomoddirectives
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ifshort
|
||||
- importas
|
||||
- ineffassign
|
||||
- lll
|
||||
- makezero
|
||||
- misspell
|
||||
- nakedret
|
||||
- nestif
|
||||
- nilerr
|
||||
- nilnil
|
||||
- noctx
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- predeclared
|
||||
- predeclared
|
||||
- promlinter
|
||||
- revive
|
||||
- rowserrcheck
|
||||
- sqlclosecheck
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- tenv
|
||||
- thelper
|
||||
- tparallel
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- varcheck
|
||||
- wastedassign
|
||||
- whitespace
|
||||
|
||||
run:
|
||||
|
||||
80
Dockerfile
80
Dockerfile
@@ -2,7 +2,7 @@ ARG ALPINE_VERSION=3.14
|
||||
ARG GO_ALPINE_VERSION=3.14
|
||||
ARG GO_VERSION=1.17
|
||||
ARG XCPUTRANSLATE_VERSION=v0.6.0
|
||||
ARG GOLANGCI_LINT_VERSION=v1.41.1
|
||||
ARG GOLANGCI_LINT_VERSION=v1.43.0
|
||||
ARG BUILDPLATFORM=linux/amd64
|
||||
|
||||
FROM --platform=${BUILDPLATFORM} qmcgaw/xcputranslate:${XCPUTRANSLATE_VERSION} AS xcputranslate
|
||||
@@ -67,60 +67,68 @@ LABEL \
|
||||
org.opencontainers.image.title="VPN swiss-knife like client for multiple VPN providers" \
|
||||
org.opencontainers.image.description="VPN swiss-knife like client to tunnel to multiple VPN servers using OpenVPN, IPtables, DNS over TLS, Shadowsocks, an HTTP proxy and Alpine Linux"
|
||||
ENV VPNSP=pia \
|
||||
VERSION_INFORMATION=on \
|
||||
VPN_TYPE=openvpn \
|
||||
PROTOCOL=udp \
|
||||
# OpenVPN
|
||||
OPENVPN_PROTOCOL=udp \
|
||||
OPENVPN_USER= \
|
||||
OPENVPN_PASSWORD= \
|
||||
OPENVPN_USER_SECRETFILE=/run/secrets/openvpn_user \
|
||||
OPENVPN_PASSWORD_SECRETFILE=/run/secrets/openvpn_password \
|
||||
OPENVPN_VERSION=2.5 \
|
||||
OPENVPN_VERBOSITY=1 \
|
||||
OPENVPN_FLAGS= \
|
||||
OPENVPN_CIPHER= \
|
||||
OPENVPN_AUTH= \
|
||||
OPENVPN_ROOT=yes \
|
||||
OPENVPN_TARGET_IP= \
|
||||
OPENVPN_IPV6=off \
|
||||
OPENVPN_CUSTOM_CONFIG= \
|
||||
OPENVPN_INTERFACE=tun0 \
|
||||
OPENVPN_PORT= \
|
||||
# Wireguard
|
||||
WIREGUARD_PRIVATE_KEY= \
|
||||
WIREGUARD_PRESHARED_KEY= \
|
||||
WIREGUARD_PUBLIC_KEY= \
|
||||
WIREGUARD_ADDRESS= \
|
||||
WIREGUARD_PORT= \
|
||||
WIREGUARD_ENDPOINT_IP= \
|
||||
WIREGUARD_ENDPOINT_PORT= \
|
||||
WIREGUARD_INTERFACE=wg0 \
|
||||
TZ= \
|
||||
PUID= \
|
||||
PGID= \
|
||||
PUBLICIP_FILE="/tmp/gluetun/ip" \
|
||||
# VPN provider settings
|
||||
OPENVPN_USER= \
|
||||
OPENVPN_PASSWORD= \
|
||||
USER_SECRETFILE=/run/secrets/openvpn_user \
|
||||
PASSWORD_SECRETFILE=/run/secrets/openvpn_password \
|
||||
# VPN server filtering
|
||||
REGION= \
|
||||
COUNTRY= \
|
||||
CITY= \
|
||||
PORT= \
|
||||
SERVER_HOSTNAME= \
|
||||
# Mullvad only:
|
||||
# # Mullvad only:
|
||||
ISP= \
|
||||
OWNED=no \
|
||||
# Private Internet Access only:
|
||||
# # Private Internet Access only:
|
||||
PIA_ENCRYPTION=strong \
|
||||
PORT_FORWARDING=off \
|
||||
PORT_FORWARDING_STATUS_FILE="/tmp/gluetun/forwarded_port" \
|
||||
# Cyberghost only:
|
||||
CYBERGHOST_GROUP="Premium UDP Europe" \
|
||||
# # Cyberghost only:
|
||||
OPENVPN_CLIENTCRT_SECRETFILE=/run/secrets/openvpn_clientcrt \
|
||||
OPENVPN_CLIENTKEY_SECRETFILE=/run/secrets/openvpn_clientkey \
|
||||
# Nordvpn only:
|
||||
# # Nordvpn only:
|
||||
SERVER_NUMBER= \
|
||||
# NordVPN and ProtonVPN only:
|
||||
# # PIA and ProtonVPN only:
|
||||
SERVER_NAME= \
|
||||
# ProtonVPN only:
|
||||
# # ProtonVPN only:
|
||||
FREE_ONLY= \
|
||||
# Openvpn
|
||||
OPENVPN_CIPHER= \
|
||||
OPENVPN_AUTH= \
|
||||
# # Surfshark only:
|
||||
MULTIHOP_ONLY= \
|
||||
# Firewall
|
||||
FIREWALL=on \
|
||||
FIREWALL_VPN_INPUT_PORTS= \
|
||||
FIREWALL_INPUT_PORTS= \
|
||||
FIREWALL_OUTBOUND_SUBNETS= \
|
||||
FIREWALL_DEBUG=off \
|
||||
# Logging
|
||||
LOG_LEVEL=info \
|
||||
# Health
|
||||
HEALTH_OPENVPN_DURATION_INITIAL=6s \
|
||||
HEALTH_OPENVPN_DURATION_ADDITION=5s \
|
||||
HEALTH_SERVER_ADDRESS=127.0.0.1:9999 \
|
||||
HEALTH_ADDRESS_TO_PING=github.com \
|
||||
HEALTH_VPN_DURATION_INITIAL=6s \
|
||||
HEALTH_VPN_DURATION_ADDITION=5s \
|
||||
# DNS over TLS
|
||||
DOT=on \
|
||||
DOT_PROVIDERS=cloudflare \
|
||||
@@ -137,12 +145,6 @@ ENV VPNSP=pia \
|
||||
DNS_UPDATE_PERIOD=24h \
|
||||
DNS_PLAINTEXT_ADDRESS=1.1.1.1 \
|
||||
DNS_KEEP_NAMESERVER=off \
|
||||
# Firewall
|
||||
FIREWALL=on \
|
||||
FIREWALL_VPN_INPUT_PORTS= \
|
||||
FIREWALL_INPUT_PORTS= \
|
||||
FIREWALL_OUTBOUND_SUBNETS= \
|
||||
FIREWALL_DEBUG=off \
|
||||
# HTTP proxy
|
||||
HTTPPROXY= \
|
||||
HTTPPROXY_LOG=off \
|
||||
@@ -158,7 +160,16 @@ ENV VPNSP=pia \
|
||||
SHADOWSOCKS_PASSWORD= \
|
||||
SHADOWSOCKS_PASSWORD_SECRETFILE=/run/secrets/shadowsocks_password \
|
||||
SHADOWSOCKS_CIPHER=chacha20-ietf-poly1305 \
|
||||
UPDATER_PERIOD=0
|
||||
# Server data updater
|
||||
UPDATER_PERIOD=0 \
|
||||
# Public IP
|
||||
PUBLICIP_FILE="/tmp/gluetun/ip" \
|
||||
PUBLICIP_PERIOD=12h \
|
||||
# Extras
|
||||
VERSION_INFORMATION=on \
|
||||
TZ= \
|
||||
PUID= \
|
||||
PGID=
|
||||
ENTRYPOINT ["/entrypoint"]
|
||||
EXPOSE 8000/tcp 8888/tcp 8388/tcp 8388/udp
|
||||
HEALTHCHECK --interval=5s --timeout=5s --start-period=10s --retries=1 CMD /entrypoint healthcheck
|
||||
@@ -168,6 +179,9 @@ RUN apk add --no-cache --update -l apk-tools && \
|
||||
mv /usr/sbin/openvpn /usr/sbin/openvpn2.4 && \
|
||||
apk del openvpn && \
|
||||
apk add --no-cache --update openvpn ca-certificates iptables ip6tables unbound tzdata && \
|
||||
mv /usr/sbin/openvpn /usr/sbin/openvpn2.5 && \
|
||||
# Fix vulnerability issue
|
||||
apk add --no-cache --update busybox && \
|
||||
rm -rf /var/cache/apk/* /etc/unbound/* /usr/sbin/unbound-* /etc/openvpn/*.sh /usr/lib/openvpn/plugins/openvpn-plugin-down-root.so && \
|
||||
deluser openvpn && \
|
||||
deluser unbound && \
|
||||
|
||||
107
README.md
107
README.md
@@ -1,9 +1,9 @@
|
||||
# Gluetun VPN client
|
||||
|
||||
*Lightweight swiss-knife-like VPN client to tunnel to Cyberghost, FastestVPN,
|
||||
HideMyAss, IPVanish, IVPN, Mullvad, NordVPN, Privado, Private Internet Access, PrivateVPN,
|
||||
ProtonVPN, PureVPN, Surfshark, TorGuard, VPNUnlimited, VyprVPN and Windscribe VPN servers
|
||||
using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
|
||||
*Lightweight swiss-knife-like VPN client to tunnel to Cyberghost, ExpressVPN, FastestVPN,
|
||||
HideMyAss, IPVanish, IVPN, Mullvad, NordVPN, Perfect Privacy, Privado, Private Internet Access, PrivateVPN,
|
||||
ProtonVPN, PureVPN, Surfshark, TorGuard, VPNUnlimited, VyprVPN, WeVPN and Windscribe VPN servers
|
||||
using Go, OpenVPN or Wireguard, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
|
||||
|
||||
**ANNOUNCEMENT**: Wireguard is now supported for all providers supporting it!
|
||||
|
||||
@@ -40,10 +40,14 @@ using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
|
||||
|
||||
## Quick links
|
||||
|
||||
- Problem or suggestion?
|
||||
- [Start a discussion](https://github.com/qdm12/gluetun/discussions)
|
||||
- [Create an issue](https://github.com/qdm12/gluetun/issues)
|
||||
- [Setup](#Setup)
|
||||
- [Features](#Features)
|
||||
- Problem?
|
||||
- [Check the Wiki](https://github.com/qdm12/gluetun/wiki)
|
||||
- [Start a discussion](https://github.com/qdm12/gluetun/discussions)
|
||||
- [Fix the Unraid template](https://github.com/qdm12/gluetun/discussions/550)
|
||||
- Suggestion?
|
||||
- [Create an issue](https://github.com/qdm12/gluetun/issues)
|
||||
- [Join the Slack channel](https://join.slack.com/t/qdm12/shared_invite/enQtOTE0NjcxNTM1ODc5LTYyZmVlOTM3MGI4ZWU0YmJkMjUxNmQ4ODQ2OTAwYzMxMTlhY2Q1MWQyOWUyNjc2ODliNjFjMDUxNWNmNzk5MDk)
|
||||
- Happy?
|
||||
- Sponsor me on [github.com/sponsors/qdm12](https://github.com/sponsors/qdm12)
|
||||
@@ -53,69 +57,68 @@ using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
|
||||
|
||||
[](https://youtu.be/0F6I03LQcI4)
|
||||
|
||||
- [Substack Console interview](https://console.substack.com/p/console-72)
|
||||
|
||||
## Features
|
||||
|
||||
- Based on Alpine 3.14 for a small Docker image of 31MB
|
||||
- Supports: **Cyberghost**, **FastestVPN**, **HideMyAss**, **IPVanish**, **IVPN**, **Mullvad**, **NordVPN**, **Privado**, **Private Internet Access**, **PrivateVPN**, **ProtonVPN**, **PureVPN**, **Surfshark**, **TorGuard**, **VPNUnlimited**, **Vyprvpn**, **Windscribe** servers
|
||||
- Supports OpenVPN
|
||||
- Supports Wireguard for **Mullvad** and **Windscribe** (more in progress, see #134)
|
||||
- Based on Alpine 3.14 for a small Docker image of 33MB
|
||||
- Supports: **Cyberghost**, **ExpressVPN**, **FastestVPN**, **HideMyAss**, **IPVanish**, **IVPN**, **Mullvad**, **NordVPN**, **Perfect Privacy**, **Privado**, **Private Internet Access**, **PrivateVPN**, **ProtonVPN**, **PureVPN**, **Surfshark**, **TorGuard**, **VPNUnlimited**, **Vyprvpn**, **WeVPN**, **Windscribe** servers
|
||||
- Supports OpenVPN for all providers listed
|
||||
- Supports Wireguard
|
||||
- For **Mullvad**, **Ivpn** and **Windscribe**
|
||||
- For **Torguard**, **VPN Unlimited** and **WeVPN** using [the custom provider](https://github.com/qdm12/gluetun/wiki/Custom-provider)
|
||||
- For custom Wireguard configurations using [the custom provider](https://github.com/qdm12/gluetun/wiki/Custom-provider)
|
||||
- More in progress, see [#134](https://github.com/qdm12/gluetun/issues/134)
|
||||
- DNS over TLS baked in with service provider(s) of your choice
|
||||
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours
|
||||
- Choose the vpn network protocol, `udp` or `tcp`
|
||||
- Built in firewall kill switch to allow traffic only with needed the VPN servers and LAN devices
|
||||
- Built in Shadowsocks proxy (protocol based on SOCKS5 with an encryption layer, tunnels TCP+UDP)
|
||||
- Built in HTTP proxy (tunnels HTTP and HTTPS through TCP)
|
||||
- [Connect other containers to it](https://github.com/qdm12/gluetun/wiki/Connect-to-gluetun)
|
||||
- [Connect LAN devices to it](https://github.com/qdm12/gluetun/wiki/Connect-to-gluetun)
|
||||
- [Connect other containers to it](https://github.com/qdm12/gluetun/wiki/Connect-a-container-to-gluetun)
|
||||
- [Connect LAN devices to it](https://github.com/qdm12/gluetun/wiki/Connect-a-LAN-device-to-gluetun)
|
||||
- Compatible with amd64, i686 (32 bit), **ARM** 64 bit, ARM 32 bit v6 and v7, and even ppc64le 🎆
|
||||
- VPN server side port forwarding for Private Internet Access and Vyprvpn
|
||||
- [Custom VPN server side port forwarding for Private Internet Access](https://github.com/qdm12/gluetun/wiki/Private-internet-access#vpn-server-port-forwarding)
|
||||
- Possibility of split horizon DNS by selecting multiple DNS over TLS providers
|
||||
- Subprograms all drop root privileges once launched
|
||||
- Subprograms output streams are all merged together
|
||||
- Unbound subprogram drops root privileges once launched
|
||||
- Can work as a Kubernetes sidecar container, thanks @rorph
|
||||
|
||||
## Setup
|
||||
|
||||
1. Ensure your `tun` kernel module is setup:
|
||||
🎉 There are now instructions specific to each VPN provider with examples to help you get started as quickly as possible!
|
||||
|
||||
```sh
|
||||
sudo modprobe tun
|
||||
# or, if you don't have modprobe, with
|
||||
sudo insmod /lib/modules/tun.ko
|
||||
```
|
||||
Go to the [Wiki](https://github.com/qdm12/gluetun/wiki)!
|
||||
|
||||
1. Extra steps:
|
||||
- [For Synology users](https://github.com/qdm12/gluetun/wiki/Synology-setup)
|
||||
- [For 32 bit Operating systems (**Rasberry Pis**)](https://github.com/qdm12/gluetun/wiki/32-bit-setup)
|
||||
1. Launch the container with:
|
||||
[🐛 Found a bug in the Wiki?!](https://github.com/qdm12/gluetun/issues/new?assignees=&labels=%F0%9F%93%84+Wiki+issue&template=wiki+issue.yml&title=Wiki+issue%3A+)
|
||||
|
||||
```bash
|
||||
docker run -d --name gluetun --cap-add=NET_ADMIN \
|
||||
-e VPNSP="private internet access" -e REGION="CA Montreal" \
|
||||
-e OPENVPN_USER=js89ds7 -e OPENVPN_PASSWORD=8fd9s239G \
|
||||
-v /yourpath:/gluetun \
|
||||
qmcgaw/gluetun
|
||||
```
|
||||
Here's a docker-compose.yml for the laziest:
|
||||
|
||||
or use [docker-compose.yml](https://github.com/qdm12/gluetun/blob/master/docker-compose.yml) with:
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
You should probably check the many [environment variables](https://github.com/qdm12/gluetun/wiki/Environment-variables) available to adapt the container to your needs.
|
||||
|
||||
## Further setup
|
||||
|
||||
The following points are all optional but should give you insights on all the possibilities with this container.
|
||||
|
||||
- [Test your setup](https://github.com/qdm12/gluetun/wiki/Test-your-setup)
|
||||
- [How to connect other containers and devices to Gluetun](https://github.com/qdm12/gluetun/wiki/Connect-to-gluetun)
|
||||
- [How to use Wireguard](https://github.com/qdm12/gluetun/wiki/Wireguard)
|
||||
- [VPN server side port forwarding](https://github.com/qdm12/gluetun/wiki/Port-forwarding)
|
||||
- [HTTP control server](https://github.com/qdm12/gluetun/wiki/HTTP-Control-server) to automate things, restart Openvpn etc.
|
||||
- Update the image with `docker pull qmcgaw/gluetun:latest`. See this [Wiki document](https://github.com/qdm12/gluetun/wiki/Docker-image-tags) for Docker tags available.
|
||||
- Use [Docker secrets](https://github.com/qdm12/gluetun/wiki/Docker-secrets) to read your credentials instead of environment variables
|
||||
```yml
|
||||
version: "3"
|
||||
services:
|
||||
gluetun:
|
||||
image: qmcgaw/gluetun
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
ports:
|
||||
- 8888:8888/tcp # HTTP proxy
|
||||
- 8388:8388/tcp # Shadowsocks
|
||||
- 8388:8388/udp # Shadowsocks
|
||||
volumes:
|
||||
- /yourpath:/gluetun
|
||||
environment:
|
||||
# See https://github.com/qdm12/gluetun/wiki
|
||||
- VPNSP=ivpn
|
||||
- VPN_TYPE=openvpn
|
||||
# OpenVPN:
|
||||
- OPENVPN_USER=
|
||||
- OPENVPN_PASSWORD=
|
||||
# Wireguard:
|
||||
# - WIREGUARD_PRIVATE_KEY=wOEI9rqqbDwnN8/Bpp22sVz48T71vJ4fYmFWujulwUU=
|
||||
# - WIREGUARD_ADDRESS=10.64.222.21/32
|
||||
# Timezone for accurate log times
|
||||
- TZ=
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
_ "time/tzdata"
|
||||
|
||||
_ "github.com/breml/rootcerts"
|
||||
"github.com/qdm12/dns/pkg/unbound"
|
||||
"github.com/qdm12/gluetun/internal/alpine"
|
||||
"github.com/qdm12/gluetun/internal/cli"
|
||||
@@ -37,6 +39,9 @@ import (
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/params"
|
||||
"github.com/qdm12/goshutdown"
|
||||
"github.com/qdm12/goshutdown/goroutine"
|
||||
"github.com/qdm12/goshutdown/group"
|
||||
"github.com/qdm12/goshutdown/order"
|
||||
"github.com/qdm12/gosplash"
|
||||
"github.com/qdm12/updated/pkg/dnscrypto"
|
||||
)
|
||||
@@ -130,17 +135,49 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
return cli.OpenvpnConfig(logger, env)
|
||||
case "update":
|
||||
return cli.Update(ctx, args[2:], logger)
|
||||
case "format-servers":
|
||||
return cli.FormatServers(args[2:])
|
||||
default:
|
||||
return fmt.Errorf("%w: %s", errCommandUnknown, args[1])
|
||||
}
|
||||
}
|
||||
|
||||
announcementExp, err := time.Parse(time.RFC3339, "2021-10-02T00:00:00Z")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
splashSettings := gosplash.Settings{
|
||||
User: "qdm12",
|
||||
Repository: "gluetun",
|
||||
Emails: []string{"quentin.mcgaw@gmail.com"},
|
||||
Version: buildInfo.Version,
|
||||
Commit: buildInfo.Commit,
|
||||
BuildDate: buildInfo.Created,
|
||||
Announcement: "Wireguard is now supported for Mullvad, IVPN and Windscribe!",
|
||||
AnnounceExp: announcementExp,
|
||||
// Sponsor information
|
||||
PaypalUser: "qmcgaw",
|
||||
GithubSponsor: "qdm12",
|
||||
}
|
||||
for _, line := range gosplash.MakeLines(splashSettings) {
|
||||
fmt.Println(line)
|
||||
}
|
||||
|
||||
// TODO run this in a loop or in openvpn to reload from file without restarting
|
||||
storageLogger := logger.NewChild(logging.Settings{Prefix: "storage: "})
|
||||
storage, err := storage.New(storageLogger, constants.ServersData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
allServers := storage.GetServers()
|
||||
|
||||
var allSettings configuration.Settings
|
||||
err := allSettings.Read(env,
|
||||
err = allSettings.Read(env, allServers,
|
||||
logger.NewChild(logging.Settings{Prefix: "configuration: "}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.PatchLevel(allSettings.Log.Level)
|
||||
|
||||
puid, pgid := allSettings.System.PUID, allSettings.System.PGID
|
||||
|
||||
@@ -156,27 +193,6 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
dnsConf := unbound.NewConfigurator(nil, cmder, dnsCrypto,
|
||||
"/etc/unbound", "/usr/sbin/unbound", cacertsPath)
|
||||
|
||||
announcementExp, err := time.Parse(time.RFC3339, "2021-10-02T00:00:00Z")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
splashSettings := gosplash.Settings{
|
||||
User: "qdm12",
|
||||
Repository: "gluetun",
|
||||
Emails: []string{"quentin.mcgaw@gmail.com"},
|
||||
Version: buildInfo.Version,
|
||||
Commit: buildInfo.Commit,
|
||||
BuildDate: buildInfo.Created,
|
||||
Announcement: "Wireguard is now supported!",
|
||||
AnnounceExp: announcementExp,
|
||||
// Sponsor information
|
||||
PaypalUser: "qmcgaw",
|
||||
GithubSponsor: "qdm12",
|
||||
}
|
||||
for _, line := range gosplash.MakeLines(splashSettings) {
|
||||
fmt.Println(line)
|
||||
}
|
||||
|
||||
err = printVersions(ctx, logger, []printVersionElement{
|
||||
{name: "Alpine", getVersion: alpineConf.Version},
|
||||
{name: "OpenVPN 2.4", getVersion: ovpnConf.Version24},
|
||||
@@ -199,15 +215,6 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO run this in a loop or in openvpn to reload from file without restarting
|
||||
storage := storage.New(
|
||||
logger.NewChild(logging.Settings{Prefix: "storage: "}),
|
||||
constants.ServersData)
|
||||
allServers, err := storage.SyncServers(constants.GetAllServers())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const defaultUsername = "nonrootuser"
|
||||
nonRootUsername, err := alpineConf.CreateUser(defaultUsername, puid)
|
||||
if err != nil {
|
||||
@@ -225,7 +232,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
return err
|
||||
}
|
||||
|
||||
firewallLogLevel := logging.LevelInfo
|
||||
firewallLogLevel := allSettings.Log.Level
|
||||
if allSettings.Firewall.Debug {
|
||||
firewallLogLevel = logging.LevelDebug
|
||||
}
|
||||
@@ -233,7 +240,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
Prefix: "routing: ",
|
||||
Level: firewallLogLevel,
|
||||
})
|
||||
routingConf := routing.NewRouting(routingLogger)
|
||||
routingConf := routing.New(netLinker, routingLogger)
|
||||
|
||||
defaultInterface, defaultGateway, err := routingConf.DefaultRoute()
|
||||
if err != nil {
|
||||
@@ -292,13 +299,6 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
}
|
||||
}
|
||||
|
||||
for _, vpnPort := range allSettings.Firewall.VPNInputPorts {
|
||||
err = firewallConf.SetAllowedPort(ctx, vpnPort, allSettings.VPN.OpenVPN.Interface)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, port := range allSettings.Firewall.InputPorts {
|
||||
err = firewallConf.SetAllowedPort(ctx, port, defaultInterface)
|
||||
if err != nil {
|
||||
@@ -307,6 +307,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
} // TODO move inside firewall?
|
||||
|
||||
// Shutdown settings
|
||||
const totalShutdownTimeout = 3 * time.Second
|
||||
const defaultShutdownTimeout = 400 * time.Millisecond
|
||||
defaultShutdownOnSuccess := func(goRoutineName string) {
|
||||
logger.Info(goRoutineName + ": terminated ✔️")
|
||||
@@ -314,34 +315,32 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
defaultShutdownOnFailure := func(goRoutineName string, err error) {
|
||||
logger.Warn(goRoutineName + ": " + err.Error() + " ⚠️")
|
||||
}
|
||||
defaultGoRoutineSettings := goshutdown.GoRoutineSettings{Timeout: defaultShutdownTimeout}
|
||||
defaultGroupSettings := goshutdown.GroupSettings{
|
||||
Timeout: defaultShutdownTimeout,
|
||||
OnSuccess: defaultShutdownOnSuccess,
|
||||
}
|
||||
defaultGroupOptions := []group.Option{
|
||||
group.OptionTimeout(defaultShutdownTimeout),
|
||||
group.OptionOnSuccess(defaultShutdownOnSuccess)}
|
||||
|
||||
controlGroupHandler := goshutdown.NewGroupHandler("control", defaultGroupSettings)
|
||||
tickersGroupHandler := goshutdown.NewGroupHandler("tickers", defaultGroupSettings)
|
||||
otherGroupHandler := goshutdown.NewGroupHandler("other", defaultGroupSettings)
|
||||
controlGroupHandler := goshutdown.NewGroupHandler("control", defaultGroupOptions...)
|
||||
tickersGroupHandler := goshutdown.NewGroupHandler("tickers", defaultGroupOptions...)
|
||||
otherGroupHandler := goshutdown.NewGroupHandler("other", defaultGroupOptions...)
|
||||
|
||||
portForwardLogger := logger.NewChild(logging.Settings{Prefix: "port forwarding: "})
|
||||
portForwardLooper := portforward.NewLoop(allSettings.VPN.Provider.PortForwarding,
|
||||
httpClient, firewallConf, portForwardLogger)
|
||||
portForwardHandler, portForwardCtx, portForwardDone := goshutdown.NewGoRoutineHandler(
|
||||
"port forwarding", goshutdown.GoRoutineSettings{Timeout: time.Second})
|
||||
"port forwarding", goroutine.OptionTimeout(time.Second))
|
||||
go portForwardLooper.Run(portForwardCtx, portForwardDone)
|
||||
|
||||
unboundLogger := logger.NewChild(logging.Settings{Prefix: "dns over tls: "})
|
||||
unboundLooper := dns.NewLoop(dnsConf, allSettings.DNS, httpClient,
|
||||
unboundLogger)
|
||||
dnsHandler, dnsCtx, dnsDone := goshutdown.NewGoRoutineHandler(
|
||||
"unbound", defaultGoRoutineSettings)
|
||||
"unbound", goroutine.OptionTimeout(defaultShutdownTimeout))
|
||||
// wait for unboundLooper.Restart or its ticker launched with RunRestartTicker
|
||||
go unboundLooper.Run(dnsCtx, dnsDone)
|
||||
otherGroupHandler.Add(dnsHandler)
|
||||
|
||||
dnsTickerHandler, dnsTickerCtx, dnsTickerDone := goshutdown.NewGoRoutineHandler(
|
||||
"dns ticker", defaultGoRoutineSettings)
|
||||
"dns ticker", goroutine.OptionTimeout(defaultShutdownTimeout))
|
||||
go unboundLooper.RunRestartTicker(dnsTickerCtx, dnsTickerDone)
|
||||
controlGroupHandler.Add(dnsTickerHandler)
|
||||
|
||||
@@ -349,35 +348,35 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
logger.NewChild(logging.Settings{Prefix: "ip getter: "}),
|
||||
allSettings.PublicIP, puid, pgid)
|
||||
pubIPHandler, pubIPCtx, pubIPDone := goshutdown.NewGoRoutineHandler(
|
||||
"public IP", defaultGoRoutineSettings)
|
||||
"public IP", goroutine.OptionTimeout(defaultShutdownTimeout))
|
||||
go publicIPLooper.Run(pubIPCtx, pubIPDone)
|
||||
otherGroupHandler.Add(pubIPHandler)
|
||||
|
||||
pubIPTickerHandler, pubIPTickerCtx, pubIPTickerDone := goshutdown.NewGoRoutineHandler(
|
||||
"public IP", defaultGoRoutineSettings)
|
||||
"public IP", goroutine.OptionTimeout(defaultShutdownTimeout))
|
||||
go publicIPLooper.RunRestartTicker(pubIPTickerCtx, pubIPTickerDone)
|
||||
tickersGroupHandler.Add(pubIPTickerHandler)
|
||||
|
||||
vpnLogger := logger.NewChild(logging.Settings{Prefix: "vpn: "})
|
||||
vpnLooper := vpn.NewLoop(allSettings.VPN,
|
||||
vpnLooper := vpn.NewLoop(allSettings.VPN, allSettings.Firewall.VPNInputPorts,
|
||||
allServers, ovpnConf, netLinker, firewallConf, routingConf, portForwardLooper,
|
||||
cmder, publicIPLooper, unboundLooper, vpnLogger, httpClient,
|
||||
buildInfo, allSettings.VersionInformation)
|
||||
vpnHandler, vpnCtx, vpnDone := goshutdown.NewGoRoutineHandler(
|
||||
"vpn", goshutdown.GoRoutineSettings{Timeout: time.Second})
|
||||
"vpn", goroutine.OptionTimeout(time.Second))
|
||||
go vpnLooper.Run(vpnCtx, vpnDone)
|
||||
|
||||
updaterLooper := updater.NewLooper(allSettings.Updater,
|
||||
allServers, storage, vpnLooper.SetServers, httpClient,
|
||||
logger.NewChild(logging.Settings{Prefix: "updater: "}))
|
||||
updaterHandler, updaterCtx, updaterDone := goshutdown.NewGoRoutineHandler(
|
||||
"updater", defaultGoRoutineSettings)
|
||||
"updater", goroutine.OptionTimeout(defaultShutdownTimeout))
|
||||
// wait for updaterLooper.Restart() or its ticket launched with RunRestartTicker
|
||||
go updaterLooper.Run(updaterCtx, updaterDone)
|
||||
tickersGroupHandler.Add(updaterHandler)
|
||||
|
||||
updaterTickerHandler, updaterTickerCtx, updaterTickerDone := goshutdown.NewGoRoutineHandler(
|
||||
"updater ticker", defaultGoRoutineSettings)
|
||||
"updater ticker", goroutine.OptionTimeout(defaultShutdownTimeout))
|
||||
go updaterLooper.RunRestartTicker(updaterTickerCtx, updaterTickerDone)
|
||||
controlGroupHandler.Add(updaterTickerHandler)
|
||||
|
||||
@@ -385,21 +384,21 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
logger.NewChild(logging.Settings{Prefix: "http proxy: "}),
|
||||
allSettings.HTTPProxy)
|
||||
httpProxyHandler, httpProxyCtx, httpProxyDone := goshutdown.NewGoRoutineHandler(
|
||||
"http proxy", defaultGoRoutineSettings)
|
||||
"http proxy", goroutine.OptionTimeout(defaultShutdownTimeout))
|
||||
go httpProxyLooper.Run(httpProxyCtx, httpProxyDone)
|
||||
otherGroupHandler.Add(httpProxyHandler)
|
||||
|
||||
shadowsocksLooper := shadowsocks.NewLooper(allSettings.ShadowSocks,
|
||||
logger.NewChild(logging.Settings{Prefix: "shadowsocks: "}))
|
||||
shadowsocksHandler, shadowsocksCtx, shadowsocksDone := goshutdown.NewGoRoutineHandler(
|
||||
"shadowsocks proxy", defaultGoRoutineSettings)
|
||||
"shadowsocks proxy", goroutine.OptionTimeout(defaultShutdownTimeout))
|
||||
go shadowsocksLooper.Run(shadowsocksCtx, shadowsocksDone)
|
||||
otherGroupHandler.Add(shadowsocksHandler)
|
||||
|
||||
controlServerAddress := ":" + strconv.Itoa(int(allSettings.ControlServer.Port))
|
||||
controlServerLogging := allSettings.ControlServer.Log
|
||||
httpServerHandler, httpServerCtx, httpServerDone := goshutdown.NewGoRoutineHandler(
|
||||
"http server", defaultGoRoutineSettings)
|
||||
"http server", goroutine.OptionTimeout(defaultShutdownTimeout))
|
||||
httpServer := server.New(httpServerCtx, controlServerAddress, controlServerLogging,
|
||||
logger.NewChild(logging.Settings{Prefix: "http server: "}),
|
||||
buildInfo, vpnLooper, portForwardLooper, unboundLooper, updaterLooper, publicIPLooper)
|
||||
@@ -409,16 +408,13 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
healthLogger := logger.NewChild(logging.Settings{Prefix: "healthcheck: "})
|
||||
healthcheckServer := healthcheck.NewServer(allSettings.Health, healthLogger, vpnLooper)
|
||||
healthServerHandler, healthServerCtx, healthServerDone := goshutdown.NewGoRoutineHandler(
|
||||
"HTTP health server", defaultGoRoutineSettings)
|
||||
"HTTP health server", goroutine.OptionTimeout(defaultShutdownTimeout))
|
||||
go healthcheckServer.Run(healthServerCtx, healthServerDone)
|
||||
|
||||
const orderShutdownTimeout = 3 * time.Second
|
||||
orderSettings := goshutdown.OrderSettings{
|
||||
Timeout: orderShutdownTimeout,
|
||||
OnFailure: defaultShutdownOnFailure,
|
||||
OnSuccess: defaultShutdownOnSuccess,
|
||||
}
|
||||
orderHandler := goshutdown.NewOrder("gluetun", orderSettings)
|
||||
orderHandler := goshutdown.NewOrderHandler("gluetun",
|
||||
order.OptionTimeout(totalShutdownTimeout),
|
||||
order.OptionOnSuccess(defaultShutdownOnSuccess),
|
||||
order.OptionOnFailure(defaultShutdownOnFailure))
|
||||
orderHandler.Append(controlGroupHandler, tickersGroupHandler, healthServerHandler,
|
||||
vpnHandler, portForwardHandler, otherGroupHandler)
|
||||
|
||||
@@ -436,7 +432,11 @@ type printVersionElement struct {
|
||||
getVersion func(ctx context.Context) (version string, err error)
|
||||
}
|
||||
|
||||
func printVersions(ctx context.Context, logger logging.Logger,
|
||||
type infoer interface {
|
||||
Info(s string)
|
||||
}
|
||||
|
||||
func printVersions(ctx context.Context, logger infoer,
|
||||
elements []printVersionElement) (err error) {
|
||||
const timeout = 5 * time.Second
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
version: "3.7"
|
||||
services:
|
||||
gluetun:
|
||||
image: qmcgaw/gluetun
|
||||
container_name: gluetun
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
network_mode: bridge
|
||||
ports:
|
||||
- 8888:8888/tcp # HTTP proxy
|
||||
- 8388:8388/tcp # Shadowsocks
|
||||
- 8388:8388/udp # Shadowsocks
|
||||
- 8000:8000/tcp # Built-in HTTP control server
|
||||
# command:
|
||||
volumes:
|
||||
- /yourpath:/gluetun
|
||||
environment:
|
||||
# More variables are available, see the Wiki table
|
||||
- OPENVPN_USER=
|
||||
- OPENVPN_PASSWORD=
|
||||
- VPNSP=private internet access
|
||||
- VPN_TYPE=openvpn
|
||||
# Timezone for accurate logs times
|
||||
- TZ=
|
||||
restart: always
|
||||
12
go.mod
12
go.mod
@@ -3,11 +3,13 @@ module github.com/qdm12/gluetun
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/fatih/color v1.12.0
|
||||
github.com/breml/rootcerts v0.2.0
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/go-ping/ping v0.0.0-20210911151512-381826476871
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/qdm12/dns v1.11.0
|
||||
github.com/qdm12/golibs v0.0.0-20210822203818-5c568b0777b6
|
||||
github.com/qdm12/goshutdown v0.1.0
|
||||
github.com/qdm12/goshutdown v0.3.0
|
||||
github.com/qdm12/gosplash v0.1.0
|
||||
github.com/qdm12/ss-server v0.3.0
|
||||
github.com/qdm12/updated v0.0.0-20210603204757-205acfe6937e
|
||||
@@ -22,9 +24,10 @@ require (
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/google/go-cmp v0.5.5 // indirect
|
||||
github.com/google/uuid v1.2.0 // indirect
|
||||
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mdlayher/genetlink v1.0.0 // indirect
|
||||
github.com/mdlayher/netlink v1.4.0 // indirect
|
||||
github.com/miekg/dns v1.1.40 // indirect
|
||||
@@ -36,5 +39,6 @@ require (
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
|
||||
golang.org/x/net v0.0.0-20210504132125-bbd867fde50d // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||
)
|
||||
|
||||
21
go.sum
21
go.sum
@@ -4,6 +4,8 @@ github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/g
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/breml/rootcerts v0.2.0 h1:bBIgVe8bS0Ec+orgWpZ/GRYt3a0O8yoW+g2kSBY2aLE=
|
||||
github.com/breml/rootcerts v0.2.0/go.mod h1:24FDtzYMpqIeYC7QzaE8VPRQaFZU5TIUDlyk8qwjD88=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
@@ -11,8 +13,9 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
|
||||
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
@@ -29,6 +32,8 @@ github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd
|
||||
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||
github.com/go-ping/ping v0.0.0-20210911151512-381826476871 h1:wtjTfjwAR/BYYMJ+QOLI/3J/qGEI0fgrkZvgsEWK2/Q=
|
||||
github.com/go-ping/ping v0.0.0-20210911151512-381826476871/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
@@ -42,6 +47,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gotify/go-api-client/v2 v2.0.4/go.mod h1:VKiah/UK20bXsr0JObE1eBVLW44zbBouzjuri9iwjFU=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
@@ -64,10 +71,12 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kyokomi/emoji v2.2.4+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY=
|
||||
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=
|
||||
github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0=
|
||||
@@ -102,8 +111,8 @@ github.com/qdm12/golibs v0.0.0-20210603202746-e5494e9c2ebb/go.mod h1:15RBzkun0i8
|
||||
github.com/qdm12/golibs v0.0.0-20210723175634-a75ca7fd74c2/go.mod h1:6aRbg4Z/bTbm9JfxsGXfWKHi7zsOvPfUTK1S5HuAFKg=
|
||||
github.com/qdm12/golibs v0.0.0-20210822203818-5c568b0777b6 h1:bge5AL7cjHJMPz+5IOz5yF01q/l8No6+lIEBieA8gMg=
|
||||
github.com/qdm12/golibs v0.0.0-20210822203818-5c568b0777b6/go.mod h1:6aRbg4Z/bTbm9JfxsGXfWKHi7zsOvPfUTK1S5HuAFKg=
|
||||
github.com/qdm12/goshutdown v0.1.0 h1:lmwnygdXtnr2pa6VqfR/bm8077/BnBef1+7CP96B7Sw=
|
||||
github.com/qdm12/goshutdown v0.1.0/go.mod h1:/LP3MWLqI+wGH/ijfaUG+RHzBbKXIiVKnrg5vXOCf6Q=
|
||||
github.com/qdm12/goshutdown v0.3.0 h1:pqBpJkdwlZlfTEx4QHtS8u8CXx6pG0fVo6S1N0MpSEM=
|
||||
github.com/qdm12/goshutdown v0.3.0/go.mod h1:EqZ46No00kCTZ5qzdd3qIzY6ayhMt24QI8Mh8LVQYmM=
|
||||
github.com/qdm12/gosplash v0.1.0 h1:Sfl+zIjFZFP7b0iqf2l5UkmEY97XBnaKkH3FNY6Gf7g=
|
||||
github.com/qdm12/gosplash v0.1.0/go.mod h1:+A3fWW4/rUeDXhY3ieBzwghKdnIPFJgD8K3qQkenJlw=
|
||||
github.com/qdm12/ss-server v0.3.0 h1:BfKv4OU6dYb2KcDMYpTc7LIuO2jB73g3JCzy988GrLI=
|
||||
@@ -163,6 +172,7 @@ golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210504132125-bbd867fde50d h1:nTDGCTeAu2LhcsHTRzjyIUbZHCJ4QePArsm27Hka0UM=
|
||||
golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
@@ -195,6 +205,7 @@ golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
||||
@@ -8,6 +8,7 @@ type CLIer interface {
|
||||
HealthChecker
|
||||
OpenvpnConfigMaker
|
||||
Updater
|
||||
ServersFormatter
|
||||
}
|
||||
|
||||
type CLI struct {
|
||||
@@ -16,6 +17,6 @@ type CLI struct {
|
||||
|
||||
func New() *CLI {
|
||||
return &CLI{
|
||||
repoServersPath: "./internal/constants/servers.json",
|
||||
repoServersPath: "./internal/storage/servers.json",
|
||||
}
|
||||
}
|
||||
|
||||
133
internal/cli/formatservers.go
Normal file
133
internal/cli/formatservers.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/storage"
|
||||
)
|
||||
|
||||
type ServersFormatter interface {
|
||||
FormatServers(args []string) error
|
||||
}
|
||||
|
||||
var (
|
||||
ErrFormatNotRecognized = errors.New("format is not recognized")
|
||||
ErrProviderUnspecified = errors.New("VPN provider to format was not specified")
|
||||
ErrOpenOutputFile = errors.New("cannot open output file")
|
||||
ErrWriteOutput = errors.New("cannot write to output file")
|
||||
ErrCloseOutputFile = errors.New("cannot close output file")
|
||||
)
|
||||
|
||||
func (c *CLI) FormatServers(args []string) error {
|
||||
var format, output string
|
||||
var cyberghost, expressvpn, fastestvpn, hideMyAss, ipvanish, ivpn, mullvad,
|
||||
nordvpn, perfectPrivacy, pia, privado, privatevpn, protonvpn, purevpn, surfshark,
|
||||
torguard, vpnUnlimited, vyprvpn, wevpn, windscribe bool
|
||||
flagSet := flag.NewFlagSet("markdown", flag.ExitOnError)
|
||||
flagSet.StringVar(&format, "format", "markdown", "Format to use which can be: 'markdown'")
|
||||
flagSet.StringVar(&output, "output", "/dev/stdout", "Output file to write the formatted data to")
|
||||
flagSet.BoolVar(&cyberghost, "cyberghost", false, "Format Cyberghost servers")
|
||||
flagSet.BoolVar(&expressvpn, "expressvpn", false, "Format ExpressVPN servers")
|
||||
flagSet.BoolVar(&fastestvpn, "fastestvpn", false, "Format FastestVPN servers")
|
||||
flagSet.BoolVar(&hideMyAss, "hidemyass", false, "Format HideMyAss servers")
|
||||
flagSet.BoolVar(&ipvanish, "ipvanish", false, "Format IpVanish servers")
|
||||
flagSet.BoolVar(&ivpn, "ivpn", false, "Format IVPN servers")
|
||||
flagSet.BoolVar(&mullvad, "mullvad", false, "Format Mullvad servers")
|
||||
flagSet.BoolVar(&nordvpn, "nordvpn", false, "Format Nordvpn servers")
|
||||
flagSet.BoolVar(&perfectPrivacy, "perfectprivacy", false, "Format Perfect Privacy servers")
|
||||
flagSet.BoolVar(&pia, "pia", false, "Format Private Internet Access servers")
|
||||
flagSet.BoolVar(&privado, "privado", false, "Format Privado servers")
|
||||
flagSet.BoolVar(&privatevpn, "privatevpn", false, "Format Private VPN servers")
|
||||
flagSet.BoolVar(&protonvpn, "protonvpn", false, "Format Protonvpn servers")
|
||||
flagSet.BoolVar(&purevpn, "purevpn", false, "Format Purevpn servers")
|
||||
flagSet.BoolVar(&surfshark, "surfshark", false, "Format Surfshark servers")
|
||||
flagSet.BoolVar(&torguard, "torguard", false, "Format Torguard servers")
|
||||
flagSet.BoolVar(&vpnUnlimited, "vpnunlimited", false, "Format VPN Unlimited servers")
|
||||
flagSet.BoolVar(&vyprvpn, "vyprvpn", false, "Format Vyprvpn servers")
|
||||
flagSet.BoolVar(&wevpn, "wevpn", false, "Format WeVPN servers")
|
||||
flagSet.BoolVar(&windscribe, "windscribe", false, "Format Windscribe servers")
|
||||
if err := flagSet.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if format != "markdown" {
|
||||
return fmt.Errorf("%w: %s", ErrFormatNotRecognized, format)
|
||||
}
|
||||
|
||||
logger := newNoopLogger()
|
||||
storage, err := storage.New(logger, constants.ServersData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %s", ErrNewStorage, err)
|
||||
}
|
||||
currentServers := storage.GetServers()
|
||||
|
||||
var formatted string
|
||||
switch {
|
||||
case cyberghost:
|
||||
formatted = currentServers.Cyberghost.ToMarkdown()
|
||||
case expressvpn:
|
||||
formatted = currentServers.Expressvpn.ToMarkdown()
|
||||
case fastestvpn:
|
||||
formatted = currentServers.Fastestvpn.ToMarkdown()
|
||||
case hideMyAss:
|
||||
formatted = currentServers.HideMyAss.ToMarkdown()
|
||||
case ipvanish:
|
||||
formatted = currentServers.Ipvanish.ToMarkdown()
|
||||
case ivpn:
|
||||
formatted = currentServers.Ivpn.ToMarkdown()
|
||||
case mullvad:
|
||||
formatted = currentServers.Mullvad.ToMarkdown()
|
||||
case nordvpn:
|
||||
formatted = currentServers.Nordvpn.ToMarkdown()
|
||||
case perfectPrivacy:
|
||||
formatted = currentServers.Perfectprivacy.ToMarkdown()
|
||||
case pia:
|
||||
formatted = currentServers.Pia.ToMarkdown()
|
||||
case privado:
|
||||
formatted = currentServers.Privado.ToMarkdown()
|
||||
case privatevpn:
|
||||
formatted = currentServers.Privatevpn.ToMarkdown()
|
||||
case protonvpn:
|
||||
formatted = currentServers.Protonvpn.ToMarkdown()
|
||||
case purevpn:
|
||||
formatted = currentServers.Purevpn.ToMarkdown()
|
||||
case surfshark:
|
||||
formatted = currentServers.Surfshark.ToMarkdown()
|
||||
case torguard:
|
||||
formatted = currentServers.Torguard.ToMarkdown()
|
||||
case vpnUnlimited:
|
||||
formatted = currentServers.VPNUnlimited.ToMarkdown()
|
||||
case vyprvpn:
|
||||
formatted = currentServers.Vyprvpn.ToMarkdown()
|
||||
case wevpn:
|
||||
formatted = currentServers.Wevpn.ToMarkdown()
|
||||
case windscribe:
|
||||
formatted = currentServers.Windscribe.ToMarkdown()
|
||||
default:
|
||||
return ErrProviderUnspecified
|
||||
}
|
||||
|
||||
output = filepath.Clean(output)
|
||||
file, err := os.OpenFile(output, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %s", ErrOpenOutputFile, err)
|
||||
}
|
||||
|
||||
_, err = fmt.Fprint(file, formatted)
|
||||
if err != nil {
|
||||
_ = file.Close()
|
||||
return fmt.Errorf("%w: %s", ErrWriteOutput, err)
|
||||
}
|
||||
|
||||
err = file.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %s", ErrCloseOutputFile, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -8,19 +8,18 @@ import (
|
||||
|
||||
"github.com/qdm12/gluetun/internal/configuration"
|
||||
"github.com/qdm12/gluetun/internal/healthcheck"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
type HealthChecker interface {
|
||||
HealthCheck(ctx context.Context, env params.Interface, logger logging.Logger) error
|
||||
HealthCheck(ctx context.Context, env params.Interface, warner configuration.Warner) error
|
||||
}
|
||||
|
||||
func (c *CLI) HealthCheck(ctx context.Context, env params.Interface,
|
||||
logger logging.Logger) error {
|
||||
warner configuration.Warner) error {
|
||||
// Extract the health server port from the configuration.
|
||||
config := configuration.Health{}
|
||||
err := config.Read(env, logger)
|
||||
err := config.Read(env, warner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
16
internal/cli/nooplogger.go
Normal file
16
internal/cli/nooplogger.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package cli
|
||||
|
||||
import "github.com/qdm12/golibs/logging"
|
||||
|
||||
type noopLogger struct{}
|
||||
|
||||
func newNoopLogger() *noopLogger {
|
||||
return new(noopLogger)
|
||||
}
|
||||
|
||||
func (l *noopLogger) Debug(s string) {}
|
||||
func (l *noopLogger) Info(s string) {}
|
||||
func (l *noopLogger) Warn(s string) {}
|
||||
func (l *noopLogger) Error(s string) {}
|
||||
func (l *noopLogger) PatchLevel(level logging.Level) {}
|
||||
func (l *noopLogger) PatchPrefix(prefix string) {}
|
||||
@@ -9,22 +9,27 @@ import (
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/provider"
|
||||
"github.com/qdm12/gluetun/internal/storage"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
type OpenvpnConfigMaker interface {
|
||||
OpenvpnConfig(logger logging.Logger, env params.Interface) error
|
||||
OpenvpnConfig(logger OpenvpnConfigLogger, env params.Interface) error
|
||||
}
|
||||
|
||||
func (c *CLI) OpenvpnConfig(logger logging.Logger, env params.Interface) error {
|
||||
var allSettings configuration.Settings
|
||||
err := allSettings.Read(env, logger)
|
||||
type OpenvpnConfigLogger interface {
|
||||
Info(s string)
|
||||
Warn(s string)
|
||||
}
|
||||
|
||||
func (c *CLI) OpenvpnConfig(logger OpenvpnConfigLogger, env params.Interface) error {
|
||||
storage, err := storage.New(logger, constants.ServersData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
allServers, err := storage.New(logger, constants.ServersData).
|
||||
SyncServers(constants.GetAllServers())
|
||||
allServers := storage.GetServers()
|
||||
|
||||
var allSettings configuration.Settings
|
||||
err = allSettings.Read(env, allServers, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -33,7 +38,11 @@ func (c *CLI) OpenvpnConfig(logger logging.Logger, env params.Interface) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lines := providerConf.BuildConf(connection, allSettings.VPN.OpenVPN)
|
||||
lines, err := providerConf.BuildConf(connection, allSettings.VPN.OpenVPN)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(strings.Join(lines, "\n"))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -15,36 +15,43 @@ import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/storage"
|
||||
"github.com/qdm12/gluetun/internal/updater"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrModeUnspecified = errors.New("at least one of -enduser or -maintainers must be specified")
|
||||
ErrSyncServers = errors.New("cannot sync hardcoded and persisted servers")
|
||||
ErrModeUnspecified = errors.New("at least one of -enduser or -maintainer must be specified")
|
||||
ErrNewStorage = errors.New("cannot create storage")
|
||||
ErrUpdateServerInformation = errors.New("cannot update server information")
|
||||
ErrWriteToFile = errors.New("cannot write updated information to file")
|
||||
)
|
||||
|
||||
type Updater interface {
|
||||
Update(ctx context.Context, args []string, logger logging.Logger) error
|
||||
Update(ctx context.Context, args []string, logger UpdaterLogger) error
|
||||
}
|
||||
|
||||
func (c *CLI) Update(ctx context.Context, args []string, logger logging.Logger) error {
|
||||
type UpdaterLogger interface {
|
||||
Info(s string)
|
||||
Warn(s string)
|
||||
Error(s string)
|
||||
}
|
||||
|
||||
func (c *CLI) Update(ctx context.Context, args []string, logger UpdaterLogger) error {
|
||||
options := configuration.Updater{CLI: true}
|
||||
var endUserMode, maintainerMode, updateAll bool
|
||||
flagSet := flag.NewFlagSet("update", flag.ExitOnError)
|
||||
flagSet.BoolVar(&endUserMode, "enduser", false, "Write results to /gluetun/servers.json (for end users)")
|
||||
flagSet.BoolVar(&maintainerMode, "maintainer", false,
|
||||
"Write results to ./internal/constants/servers.json to modify the program (for maintainers)")
|
||||
"Write results to ./internal/storage/servers.json to modify the program (for maintainers)")
|
||||
flagSet.StringVar(&options.DNSAddress, "dns", "8.8.8.8", "DNS resolver address to use")
|
||||
flagSet.BoolVar(&updateAll, "all", false, "Update servers for all VPN providers")
|
||||
flagSet.BoolVar(&options.Cyberghost, "cyberghost", false, "Update Cyberghost servers")
|
||||
flagSet.BoolVar(&options.Expressvpn, "expressvpn", false, "Update ExpressVPN servers")
|
||||
flagSet.BoolVar(&options.Fastestvpn, "fastestvpn", false, "Update FastestVPN servers")
|
||||
flagSet.BoolVar(&options.HideMyAss, "hidemyass", false, "Update HideMyAss servers")
|
||||
flagSet.BoolVar(&options.Ipvanish, "ipvanish", false, "Update IpVanish servers")
|
||||
flagSet.BoolVar(&options.Ivpn, "ivpn", false, "Update IVPN servers")
|
||||
flagSet.BoolVar(&options.Mullvad, "mullvad", false, "Update Mullvad servers")
|
||||
flagSet.BoolVar(&options.Nordvpn, "nordvpn", false, "Update Nordvpn servers")
|
||||
flagSet.BoolVar(&options.Perfectprivacy, "perfectprivacy", false, "Update Perfect Privacy servers")
|
||||
flagSet.BoolVar(&options.PIA, "pia", false, "Update Private Internet Access post-summer 2020 servers")
|
||||
flagSet.BoolVar(&options.Privado, "privado", false, "Update Privado servers")
|
||||
flagSet.BoolVar(&options.Privatevpn, "privatevpn", false, "Update Private VPN servers")
|
||||
@@ -54,6 +61,7 @@ func (c *CLI) Update(ctx context.Context, args []string, logger logging.Logger)
|
||||
flagSet.BoolVar(&options.Torguard, "torguard", false, "Update Torguard servers")
|
||||
flagSet.BoolVar(&options.VPNUnlimited, "vpnunlimited", false, "Update VPN Unlimited servers")
|
||||
flagSet.BoolVar(&options.Vyprvpn, "vyprvpn", false, "Update Vyprvpn servers")
|
||||
flagSet.BoolVar(&options.Wevpn, "wevpn", false, "Update WeVPN servers")
|
||||
flagSet.BoolVar(&options.Windscribe, "windscribe", false, "Update Windscribe servers")
|
||||
if err := flagSet.Parse(args); err != nil {
|
||||
return err
|
||||
@@ -68,11 +76,13 @@ func (c *CLI) Update(ctx context.Context, args []string, logger logging.Logger)
|
||||
|
||||
const clientTimeout = 10 * time.Second
|
||||
httpClient := &http.Client{Timeout: clientTimeout}
|
||||
storage := storage.New(logger, constants.ServersData)
|
||||
currentServers, err := storage.SyncServers(constants.GetAllServers())
|
||||
|
||||
storage, err := storage.New(logger, constants.ServersData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %s", ErrSyncServers, err)
|
||||
return fmt.Errorf("%w: %s", ErrNewStorage, err)
|
||||
}
|
||||
currentServers := storage.GetServers()
|
||||
|
||||
updater := updater.New(options, httpClient, currentServers, logger)
|
||||
allServers, err := updater.UpdateServers(ctx)
|
||||
if err != nil {
|
||||
|
||||
95
internal/configuration/custom.go
Normal file
95
internal/configuration/custom.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
var (
|
||||
errCustomNotSupported = errors.New("custom provider is not supported")
|
||||
errCustomExtractFromFile = errors.New("cannot extract configuration from file")
|
||||
)
|
||||
|
||||
func (settings *Provider) readCustom(r reader, vpnType string) (err error) {
|
||||
settings.Name = constants.Custom
|
||||
|
||||
switch vpnType {
|
||||
case constants.OpenVPN:
|
||||
return settings.ServerSelection.OpenVPN.readCustom(r)
|
||||
case constants.Wireguard:
|
||||
return settings.ServerSelection.Wireguard.readCustom(r)
|
||||
default:
|
||||
return fmt.Errorf("%w: for VPN type %s", errCustomNotSupported, vpnType)
|
||||
}
|
||||
}
|
||||
|
||||
func (settings *OpenVPNSelection) readCustom(r reader) (err error) {
|
||||
configFile, err := r.env.Get("OPENVPN_CUSTOM_CONFIG", params.CaseSensitiveValue(), params.Compulsory())
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable OPENVPN_CUSTOM_CONFIG: %w", err)
|
||||
}
|
||||
settings.ConfFile = configFile
|
||||
|
||||
// For display and consistency purposes only,
|
||||
// these values are not actually used since the file is re-read
|
||||
// before each OpenVPN start.
|
||||
_, connection, err := r.ovpnExt.Data(configFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %s", errCustomExtractFromFile, err)
|
||||
}
|
||||
settings.TCP = connection.Protocol == constants.TCP
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (settings *OpenVPN) readCustom(r reader) (err error) {
|
||||
settings.ConfFile, err = r.env.Path("OPENVPN_CUSTOM_CONFIG",
|
||||
params.Compulsory(), params.CaseSensitiveValue())
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable OPENVPN_CUSTOM_CONFIG: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (settings *WireguardSelection) readCustom(r reader) (err error) {
|
||||
settings.PublicKey, err = r.env.Get("WIREGUARD_PUBLIC_KEY",
|
||||
params.CaseSensitiveValue(), params.Compulsory())
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable WIREGUARD_PUBLIC_KEY: %w", err)
|
||||
}
|
||||
|
||||
settings.EndpointIP, err = readWireguardEndpointIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.EndpointPort, err = r.env.Port("WIREGUARD_ENDPOINT_PORT", params.Compulsory(),
|
||||
params.RetroKeys([]string{"WIREGUARD_PORT"}, r.onRetroActive))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable WIREGUARD_ENDPOINT_PORT: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// readWireguardEndpointIP reads and parses the server endpoint IP
|
||||
// address from the environment variable WIREGUARD_ENDPOINT_IP.
|
||||
func readWireguardEndpointIP(env params.Interface) (endpointIP net.IP, err error) {
|
||||
s, err := env.Get("WIREGUARD_ENDPOINT_IP", params.Compulsory())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("environment variable WIREGUARD_ENDPOINT_IP: %w", err)
|
||||
}
|
||||
|
||||
endpointIP = net.ParseIP(s)
|
||||
if endpointIP == nil {
|
||||
return nil, fmt.Errorf("environment variable WIREGUARD_ENDPOINT_IP: %w: %s",
|
||||
ErrInvalidIP, s)
|
||||
}
|
||||
|
||||
return endpointIP, nil
|
||||
}
|
||||
@@ -4,44 +4,43 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
func (settings *Provider) readCyberghost(r reader) (err error) {
|
||||
settings.Name = constants.Cyberghost
|
||||
servers := r.servers.GetCyberghost()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Groups, err = r.env.CSVInside("CYBERGHOST_GROUP",
|
||||
constants.CyberghostGroupChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY",
|
||||
constants.CyberghostCountryChoices(servers),
|
||||
params.RetroKeys([]string{"REGION"}, r.onRetroActive))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CYBERGHOST_GROUP: %w", err)
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.CyberghostRegionChoices())
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.CyberghostHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.CyberghostHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r.env)
|
||||
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r)
|
||||
}
|
||||
|
||||
func (settings *OpenVPN) readCyberghost(r reader) (err error) {
|
||||
settings.ClientKey, err = readClientKey(r)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("%w: %s", errClientKey, err)
|
||||
}
|
||||
|
||||
settings.ClientCrt, err = readClientCertificate(r)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("%w: %s", errClientCert, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
40
internal/configuration/expressvpn.go
Normal file
40
internal/configuration/expressvpn.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
)
|
||||
|
||||
func (settings *Provider) readExpressvpn(r reader) (err error) {
|
||||
settings.Name = constants.Expressvpn
|
||||
servers := r.servers.GetExpressvpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.ExpressvpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.ExpressvpnCountriesChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.ExpressvpnCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.OpenVPN.TCP, err = readOpenVPNProtocol(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -8,21 +8,23 @@ import (
|
||||
|
||||
func (settings *Provider) readFastestvpn(r reader) (err error) {
|
||||
settings.Name = constants.Fastestvpn
|
||||
servers := r.servers.GetFastestvpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.FastestvpnHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.FastestvpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.FastestvpnCountriesChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.FastestvpnCountriesChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r)
|
||||
}
|
||||
|
||||
@@ -4,14 +4,15 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
// Health contains settings for the healthcheck and health server.
|
||||
type Health struct {
|
||||
ServerAddress string
|
||||
OpenVPN HealthyWait
|
||||
AddressToPing string
|
||||
VPN HealthyWait
|
||||
}
|
||||
|
||||
func (settings *Health) String() string {
|
||||
@@ -23,8 +24,10 @@ func (settings *Health) lines() (lines []string) {
|
||||
|
||||
lines = append(lines, indent+lastIndent+"Server address: "+settings.ServerAddress)
|
||||
|
||||
lines = append(lines, indent+lastIndent+"OpenVPN:")
|
||||
for _, line := range settings.OpenVPN.lines() {
|
||||
lines = append(lines, indent+lastIndent+"Address to ping: "+settings.AddressToPing)
|
||||
|
||||
lines = append(lines, indent+lastIndent+"VPN:")
|
||||
for _, line := range settings.VPN.lines() {
|
||||
lines = append(lines, indent+indent+line)
|
||||
}
|
||||
|
||||
@@ -32,8 +35,8 @@ func (settings *Health) lines() (lines []string) {
|
||||
}
|
||||
|
||||
// Read is to be used for the healthcheck query mode.
|
||||
func (settings *Health) Read(env params.Interface, logger logging.Logger) (err error) {
|
||||
reader := newReader(env, logger)
|
||||
func (settings *Health) Read(env params.Interface, warner Warner) (err error) {
|
||||
reader := newReader(env, models.AllServers{}, warner) // note: no need for servers data
|
||||
return settings.read(reader)
|
||||
}
|
||||
|
||||
@@ -42,20 +45,27 @@ func (settings *Health) read(r reader) (err error) {
|
||||
settings.ServerAddress, warning, err = r.env.ListeningAddress(
|
||||
"HEALTH_SERVER_ADDRESS", params.Default("127.0.0.1:9999"))
|
||||
if warning != "" {
|
||||
r.logger.Warn("environment variable HEALTH_SERVER_ADDRESS: " + warning)
|
||||
r.warner.Warn("environment variable HEALTH_SERVER_ADDRESS: " + warning)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable HEALTH_SERVER_ADDRESS: %w", err)
|
||||
}
|
||||
|
||||
settings.OpenVPN.Initial, err = r.env.Duration("HEALTH_OPENVPN_DURATION_INITIAL", params.Default("6s"))
|
||||
settings.AddressToPing, err = r.env.Get("HEALTH_ADDRESS_TO_PING", params.Default("github.com"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable HEALTH_OPENVPN_DURATION_INITIAL: %w", err)
|
||||
return fmt.Errorf("environment variable HEALTH_ADDRESS_TO_PING: %w", err)
|
||||
}
|
||||
|
||||
settings.OpenVPN.Addition, err = r.env.Duration("HEALTH_OPENVPN_DURATION_ADDITION", params.Default("5s"))
|
||||
retroKeyOption := params.RetroKeys([]string{"HEALTH_OPENVPN_DURATION_INITIAL"}, r.onRetroActive)
|
||||
settings.VPN.Initial, err = r.env.Duration("HEALTH_VPN_DURATION_INITIAL", params.Default("6s"), retroKeyOption)
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable HEALTH_OPENVPN_DURATION_ADDITION: %w", err)
|
||||
return fmt.Errorf("environment variable HEALTH_VPN_DURATION_INITIAL: %w", err)
|
||||
}
|
||||
|
||||
retroKeyOption = params.RetroKeys([]string{"HEALTH_OPENVPN_DURATION_ADDITION"}, r.onRetroActive)
|
||||
settings.VPN.Addition, err = r.env.Duration("HEALTH_VPN_DURATION_ADDITION", params.Default("5s"), retroKeyOption)
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable HEALTH_VPN_DURATION_ADDITION: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/golibs/logging/mock_logging"
|
||||
"github.com/qdm12/golibs/params/mock_params"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -15,8 +14,15 @@ import (
|
||||
func Test_Health_String(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var health Health
|
||||
const expected = "|--Health:\n |--Server address: \n |--OpenVPN:\n |--Initial duration: 0s"
|
||||
health := Health{
|
||||
ServerAddress: "a",
|
||||
AddressToPing: "b",
|
||||
}
|
||||
const expected = `|--Health:
|
||||
|--Server address: a
|
||||
|--Address to ping: b
|
||||
|--VPN:
|
||||
|--Initial duration: 0s`
|
||||
|
||||
s := health.String()
|
||||
|
||||
@@ -34,14 +40,16 @@ func Test_Health_lines(t *testing.T) {
|
||||
lines: []string{
|
||||
"|--Health:",
|
||||
" |--Server address: ",
|
||||
" |--OpenVPN:",
|
||||
" |--Address to ping: ",
|
||||
" |--VPN:",
|
||||
" |--Initial duration: 0s",
|
||||
},
|
||||
},
|
||||
"filled settings": {
|
||||
settings: Health{
|
||||
ServerAddress: "address:9999",
|
||||
OpenVPN: HealthyWait{
|
||||
AddressToPing: "github.com",
|
||||
VPN: HealthyWait{
|
||||
Initial: time.Second,
|
||||
Addition: time.Minute,
|
||||
},
|
||||
@@ -49,7 +57,8 @@ func Test_Health_lines(t *testing.T) {
|
||||
lines: []string{
|
||||
"|--Health:",
|
||||
" |--Server address: address:9999",
|
||||
" |--OpenVPN:",
|
||||
" |--Address to ping: github.com",
|
||||
" |--VPN:",
|
||||
" |--Initial duration: 1s",
|
||||
" |--Addition duration: 1m0s",
|
||||
},
|
||||
@@ -73,62 +82,127 @@ func Test_Health_read(t *testing.T) {
|
||||
|
||||
errDummy := errors.New("dummy")
|
||||
|
||||
type stringCall struct {
|
||||
call bool
|
||||
s string
|
||||
err error
|
||||
}
|
||||
|
||||
type stringCallWithWarning struct {
|
||||
call bool
|
||||
s string
|
||||
warning string
|
||||
err error
|
||||
}
|
||||
|
||||
type durationCall struct {
|
||||
call bool
|
||||
duration time.Duration
|
||||
err error
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
openvpnInitialDuration time.Duration
|
||||
openvpnInitialErr error
|
||||
openvpnAdditionDuration time.Duration
|
||||
openvpnAdditionErr error
|
||||
serverAddress string
|
||||
serverAddressWarning string
|
||||
serverAddressErr error
|
||||
expected Health
|
||||
err error
|
||||
serverAddress stringCallWithWarning
|
||||
addressToPing stringCall
|
||||
vpnInitial durationCall
|
||||
vpnAddition durationCall
|
||||
expected Health
|
||||
err error
|
||||
}{
|
||||
"success": {
|
||||
openvpnInitialDuration: time.Second,
|
||||
openvpnAdditionDuration: time.Minute,
|
||||
serverAddress: "127.0.0.1:9999",
|
||||
serverAddress: stringCallWithWarning{
|
||||
call: true,
|
||||
s: "127.0.0.1:9999",
|
||||
},
|
||||
addressToPing: stringCall{
|
||||
call: true,
|
||||
s: "1.2.3.4",
|
||||
},
|
||||
vpnInitial: durationCall{
|
||||
call: true,
|
||||
duration: time.Second,
|
||||
},
|
||||
vpnAddition: durationCall{
|
||||
call: true,
|
||||
duration: time.Minute,
|
||||
},
|
||||
expected: Health{
|
||||
ServerAddress: "127.0.0.1:9999",
|
||||
OpenVPN: HealthyWait{
|
||||
AddressToPing: "1.2.3.4",
|
||||
VPN: HealthyWait{
|
||||
Initial: time.Second,
|
||||
Addition: time.Minute,
|
||||
},
|
||||
},
|
||||
},
|
||||
"listening address error": {
|
||||
openvpnInitialDuration: time.Second,
|
||||
openvpnAdditionDuration: time.Minute,
|
||||
serverAddress: "127.0.0.1:9999",
|
||||
serverAddressWarning: "warning",
|
||||
serverAddressErr: errDummy,
|
||||
serverAddress: stringCallWithWarning{
|
||||
call: true,
|
||||
s: "127.0.0.1:9999",
|
||||
warning: "warning",
|
||||
err: errDummy,
|
||||
},
|
||||
expected: Health{
|
||||
ServerAddress: "127.0.0.1:9999",
|
||||
},
|
||||
err: errors.New("environment variable HEALTH_SERVER_ADDRESS: dummy"),
|
||||
},
|
||||
"initial error": {
|
||||
openvpnInitialDuration: time.Second,
|
||||
openvpnInitialErr: errDummy,
|
||||
openvpnAdditionDuration: time.Minute,
|
||||
"address to ping error": {
|
||||
serverAddress: stringCallWithWarning{
|
||||
call: true,
|
||||
},
|
||||
addressToPing: stringCall{
|
||||
call: true,
|
||||
s: "address",
|
||||
err: errDummy,
|
||||
},
|
||||
expected: Health{
|
||||
OpenVPN: HealthyWait{
|
||||
AddressToPing: "address",
|
||||
},
|
||||
err: errors.New("environment variable HEALTH_ADDRESS_TO_PING: dummy"),
|
||||
},
|
||||
"initial error": {
|
||||
serverAddress: stringCallWithWarning{
|
||||
call: true,
|
||||
},
|
||||
addressToPing: stringCall{
|
||||
call: true,
|
||||
},
|
||||
vpnInitial: durationCall{
|
||||
call: true,
|
||||
duration: time.Second,
|
||||
err: errDummy,
|
||||
},
|
||||
expected: Health{
|
||||
VPN: HealthyWait{
|
||||
Initial: time.Second,
|
||||
},
|
||||
},
|
||||
err: errors.New("environment variable HEALTH_OPENVPN_DURATION_INITIAL: dummy"),
|
||||
err: errors.New("environment variable HEALTH_VPN_DURATION_INITIAL: dummy"),
|
||||
},
|
||||
"addition error": {
|
||||
openvpnInitialDuration: time.Second,
|
||||
openvpnAdditionDuration: time.Minute,
|
||||
openvpnAdditionErr: errDummy,
|
||||
serverAddress: stringCallWithWarning{
|
||||
call: true,
|
||||
},
|
||||
addressToPing: stringCall{
|
||||
call: true,
|
||||
},
|
||||
vpnInitial: durationCall{
|
||||
call: true,
|
||||
duration: time.Second,
|
||||
},
|
||||
vpnAddition: durationCall{
|
||||
call: true,
|
||||
duration: time.Minute,
|
||||
err: errDummy,
|
||||
},
|
||||
expected: Health{
|
||||
OpenVPN: HealthyWait{
|
||||
VPN: HealthyWait{
|
||||
Initial: time.Second,
|
||||
Addition: time.Minute,
|
||||
},
|
||||
},
|
||||
err: errors.New("environment variable HEALTH_OPENVPN_DURATION_ADDITION: dummy"),
|
||||
err: errors.New("environment variable HEALTH_VPN_DURATION_ADDITION: dummy"),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -140,29 +214,45 @@ func Test_Health_read(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
env := mock_params.NewMockInterface(ctrl)
|
||||
logger := mock_logging.NewMockLogger(ctrl)
|
||||
warner := NewMockWarner(ctrl)
|
||||
|
||||
env.EXPECT().ListeningAddress("HEALTH_SERVER_ADDRESS", gomock.Any()).
|
||||
Return(testCase.serverAddress, testCase.serverAddressWarning,
|
||||
testCase.serverAddressErr)
|
||||
if testCase.serverAddressWarning != "" {
|
||||
logger.EXPECT().Warn("environment variable HEALTH_SERVER_ADDRESS: " + testCase.serverAddressWarning)
|
||||
if testCase.serverAddress.call {
|
||||
value := testCase.serverAddress.s
|
||||
warning := testCase.serverAddress.warning
|
||||
err := testCase.serverAddress.err
|
||||
env.EXPECT().ListeningAddress("HEALTH_SERVER_ADDRESS", gomock.Any()).
|
||||
Return(value, warning, err)
|
||||
if warning != "" {
|
||||
warner.EXPECT().Warn("environment variable HEALTH_SERVER_ADDRESS: " + warning)
|
||||
}
|
||||
}
|
||||
|
||||
if testCase.serverAddressErr == nil {
|
||||
if testCase.addressToPing.call {
|
||||
value := testCase.addressToPing.s
|
||||
err := testCase.addressToPing.err
|
||||
env.EXPECT().Get("HEALTH_ADDRESS_TO_PING", gomock.Any()).
|
||||
Return(value, err)
|
||||
}
|
||||
|
||||
if testCase.vpnInitial.call {
|
||||
value := testCase.vpnInitial.duration
|
||||
err := testCase.vpnInitial.err
|
||||
env.EXPECT().
|
||||
Duration("HEALTH_OPENVPN_DURATION_INITIAL", gomock.Any()).
|
||||
Return(testCase.openvpnInitialDuration, testCase.openvpnInitialErr)
|
||||
if testCase.openvpnInitialErr == nil {
|
||||
env.EXPECT().
|
||||
Duration("HEALTH_OPENVPN_DURATION_ADDITION", gomock.Any()).
|
||||
Return(testCase.openvpnAdditionDuration, testCase.openvpnAdditionErr)
|
||||
}
|
||||
Duration("HEALTH_VPN_DURATION_INITIAL", gomock.Any()).
|
||||
Return(value, err)
|
||||
}
|
||||
|
||||
if testCase.vpnAddition.call {
|
||||
value := testCase.vpnAddition.duration
|
||||
err := testCase.vpnAddition.err
|
||||
env.EXPECT().
|
||||
Duration("HEALTH_VPN_DURATION_ADDITION", gomock.Any()).
|
||||
Return(value, err)
|
||||
}
|
||||
|
||||
r := reader{
|
||||
env: env,
|
||||
logger: logger,
|
||||
warner: warner,
|
||||
}
|
||||
|
||||
var health Health
|
||||
|
||||
@@ -8,31 +8,33 @@ import (
|
||||
|
||||
func (settings *Provider) readHideMyAss(r reader) (err error) {
|
||||
settings.Name = constants.HideMyAss
|
||||
servers := r.servers.GetHideMyAss()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.HideMyAssCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.HideMyAssCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.HideMyAssCountryChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.HideMyAssCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.HideMyAssCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.HideMyAssCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.HideMyAssHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.HideMyAssHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r.env)
|
||||
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r)
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func (settings *HTTPProxy) read(r reader) (err error) {
|
||||
settings.Port, warning, err = r.env.ListeningPort("HTTPPROXY_PORT", params.Default("8888"),
|
||||
params.RetroKeys([]string{"TINYPROXY_PORT", "PROXY_PORT"}, r.onRetroActive))
|
||||
if len(warning) > 0 {
|
||||
r.logger.Warn(warning)
|
||||
r.warner.Warn(warning)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable HTTPPROXY_PORT (or TINYPROXY_PORT, PROXY_PORT): %w", err)
|
||||
|
||||
@@ -8,26 +8,28 @@ import (
|
||||
|
||||
func (settings *Provider) readIpvanish(r reader) (err error) {
|
||||
settings.Name = constants.Ipvanish
|
||||
servers := r.servers.GetIpvanish()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IpvanishCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IpvanishCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IpvanishCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IpvanishCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.IpvanishHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.IpvanishHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/params/mock_params"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -81,7 +82,7 @@ func Test_Provider_readIpvanish(t *testing.T) {
|
||||
settings: Provider{
|
||||
Name: constants.Ipvanish,
|
||||
},
|
||||
err: errors.New("environment variable PROTOCOL: dummy test error"),
|
||||
err: errors.New("environment variable OPENVPN_PROTOCOL: dummy test error"),
|
||||
},
|
||||
"default settings": {
|
||||
targetIP: singleStringCall{call: true},
|
||||
@@ -119,29 +120,39 @@ func Test_Provider_readIpvanish(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
servers := []models.IpvanishServer{{Hostname: "a"}}
|
||||
allServers := models.AllServers{
|
||||
Ipvanish: models.IpvanishServers{
|
||||
Servers: servers,
|
||||
},
|
||||
}
|
||||
|
||||
env := mock_params.NewMockInterface(ctrl)
|
||||
if testCase.targetIP.call {
|
||||
env.EXPECT().Get("OPENVPN_TARGET_IP").
|
||||
Return(testCase.targetIP.value, testCase.targetIP.err)
|
||||
}
|
||||
if testCase.countries.call {
|
||||
env.EXPECT().CSVInside("COUNTRY", constants.IpvanishCountryChoices()).
|
||||
env.EXPECT().CSVInside("COUNTRY", constants.IpvanishCountryChoices(servers)).
|
||||
Return(testCase.countries.values, testCase.countries.err)
|
||||
}
|
||||
if testCase.cities.call {
|
||||
env.EXPECT().CSVInside("CITY", constants.IpvanishCityChoices()).
|
||||
env.EXPECT().CSVInside("CITY", constants.IpvanishCityChoices(servers)).
|
||||
Return(testCase.cities.values, testCase.cities.err)
|
||||
}
|
||||
if testCase.hostnames.call {
|
||||
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.IpvanishHostnameChoices()).
|
||||
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.IpvanishHostnameChoices(servers)).
|
||||
Return(testCase.hostnames.values, testCase.hostnames.err)
|
||||
}
|
||||
if testCase.protocol.call {
|
||||
env.EXPECT().Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
|
||||
env.EXPECT().Inside("OPENVPN_PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
|
||||
Return(testCase.protocol.value, testCase.protocol.err)
|
||||
}
|
||||
|
||||
r := reader{env: env}
|
||||
r := reader{
|
||||
servers: allServers,
|
||||
env: env,
|
||||
}
|
||||
|
||||
var settings Provider
|
||||
err := settings.readIpvanish(r)
|
||||
|
||||
@@ -4,30 +4,70 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
func (settings *Provider) readIvpn(r reader) (err error) {
|
||||
settings.Name = constants.Ivpn
|
||||
servers := r.servers.GetIvpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IvpnCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IvpnCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IvpnCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IvpnCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.IvpnHostnameChoices())
|
||||
settings.ServerSelection.ISPs, err = r.env.CSVInside("ISP", constants.IvpnISPChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable ISP: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.IvpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||
err = settings.ServerSelection.OpenVPN.readIVPN(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return settings.ServerSelection.Wireguard.readIVPN(r.env)
|
||||
}
|
||||
|
||||
func (settings *OpenVPNSelection) readIVPN(r reader) (err error) {
|
||||
settings.TCP, err = readOpenVPNProtocol(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.CustomPort, err = readOpenVPNCustomPort(r, openvpnPortValidation{
|
||||
tcp: settings.TCP,
|
||||
allowedTCP: []uint16{80, 443, 1443},
|
||||
allowedUDP: []uint16{53, 1194, 2049, 2050},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (settings *WireguardSelection) readIVPN(env params.Interface) (err error) {
|
||||
settings.EndpointPort, err = readWireguardCustomPort(env,
|
||||
[]uint16{2049, 2050, 53, 30587, 41893, 48574, 58237})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,12 +7,13 @@ import (
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/params/mock_params"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_Provider_readIvpn(t *testing.T) {
|
||||
func Test_Provider_readIvpn(t *testing.T) { //nolint:gocognit
|
||||
t.Parallel()
|
||||
|
||||
var errDummy = errors.New("dummy test error")
|
||||
@@ -23,6 +24,15 @@ func Test_Provider_readIvpn(t *testing.T) {
|
||||
err error
|
||||
}
|
||||
|
||||
type portCall struct {
|
||||
getCall bool
|
||||
getValue string // "" or "0"
|
||||
getErr error
|
||||
portCall bool
|
||||
portValue uint16
|
||||
portErr error
|
||||
}
|
||||
|
||||
type sliceStringCall struct {
|
||||
call bool
|
||||
values []string
|
||||
@@ -30,13 +40,18 @@ func Test_Provider_readIvpn(t *testing.T) {
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
protocol singleStringCall
|
||||
targetIP singleStringCall
|
||||
countries sliceStringCall
|
||||
cities sliceStringCall
|
||||
hostnames sliceStringCall
|
||||
settings Provider
|
||||
err error
|
||||
targetIP singleStringCall
|
||||
countries sliceStringCall
|
||||
cities sliceStringCall
|
||||
isps sliceStringCall
|
||||
hostnames sliceStringCall
|
||||
protocol singleStringCall
|
||||
ovpnPort portCall
|
||||
ovpnOldPort portCall
|
||||
wgPort portCall
|
||||
wgOldPort portCall
|
||||
settings Provider
|
||||
err error
|
||||
}{
|
||||
"target IP error": {
|
||||
targetIP: singleStringCall{call: true, value: "something", err: errDummy},
|
||||
@@ -62,33 +77,78 @@ func Test_Provider_readIvpn(t *testing.T) {
|
||||
},
|
||||
err: errors.New("environment variable CITY: dummy test error"),
|
||||
},
|
||||
"isps error": {
|
||||
targetIP: singleStringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
isps: sliceStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Ivpn,
|
||||
},
|
||||
err: errors.New("environment variable ISP: dummy test error"),
|
||||
},
|
||||
"hostnames error": {
|
||||
targetIP: singleStringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
isps: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Ivpn,
|
||||
},
|
||||
err: errors.New("environment variable SERVER_HOSTNAME: dummy test error"),
|
||||
},
|
||||
"protocol error": {
|
||||
"openvpn protocol error": {
|
||||
targetIP: singleStringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
isps: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
protocol: singleStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Ivpn,
|
||||
},
|
||||
err: errors.New("environment variable PROTOCOL: dummy test error"),
|
||||
err: errors.New("environment variable OPENVPN_PROTOCOL: dummy test error"),
|
||||
},
|
||||
"default settings": {
|
||||
"openvpn custom port error": {
|
||||
targetIP: singleStringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
isps: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
protocol: singleStringCall{call: true},
|
||||
ovpnPort: portCall{getCall: true, getErr: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Ivpn,
|
||||
},
|
||||
err: errors.New("environment variable OPENVPN_PORT: dummy test error"),
|
||||
},
|
||||
"wireguard custom port error": {
|
||||
targetIP: singleStringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
isps: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
protocol: singleStringCall{call: true},
|
||||
ovpnPort: portCall{getCall: true, getValue: "0"},
|
||||
ovpnOldPort: portCall{getCall: true, getValue: "0"},
|
||||
wgPort: portCall{getCall: true, getErr: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Ivpn,
|
||||
},
|
||||
err: errors.New("environment variable WIREGUARD_ENDPOINT_PORT: dummy test error"),
|
||||
},
|
||||
"default settings": {
|
||||
targetIP: singleStringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
isps: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
protocol: singleStringCall{call: true},
|
||||
ovpnPort: portCall{getCall: true, getValue: "0"},
|
||||
ovpnOldPort: portCall{getCall: true, getValue: "0"},
|
||||
wgPort: portCall{getCall: true, getValue: "0"},
|
||||
wgOldPort: portCall{getCall: true, getValue: "0"},
|
||||
settings: Provider{
|
||||
Name: constants.Ivpn,
|
||||
},
|
||||
@@ -97,17 +157,25 @@ func Test_Provider_readIvpn(t *testing.T) {
|
||||
targetIP: singleStringCall{call: true, value: "1.2.3.4"},
|
||||
countries: sliceStringCall{call: true, values: []string{"A", "B"}},
|
||||
cities: sliceStringCall{call: true, values: []string{"C", "D"}},
|
||||
isps: sliceStringCall{call: true, values: []string{"ISP 1"}},
|
||||
hostnames: sliceStringCall{call: true, values: []string{"E", "F"}},
|
||||
protocol: singleStringCall{call: true, value: constants.TCP},
|
||||
ovpnPort: portCall{getCall: true, portCall: true, portValue: 443},
|
||||
wgPort: portCall{getCall: true, portCall: true, portValue: 2049},
|
||||
settings: Provider{
|
||||
Name: constants.Ivpn,
|
||||
ServerSelection: ServerSelection{
|
||||
OpenVPN: OpenVPNSelection{
|
||||
TCP: true,
|
||||
TCP: true,
|
||||
CustomPort: 443,
|
||||
},
|
||||
Wireguard: WireguardSelection{
|
||||
EndpointPort: 2049,
|
||||
},
|
||||
TargetIP: net.IPv4(1, 2, 3, 4),
|
||||
Countries: []string{"A", "B"},
|
||||
Cities: []string{"C", "D"},
|
||||
ISPs: []string{"ISP 1"},
|
||||
Hostnames: []string{"E", "F"},
|
||||
},
|
||||
},
|
||||
@@ -120,28 +188,75 @@ func Test_Provider_readIvpn(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
env := mock_params.NewMockInterface(ctrl)
|
||||
if testCase.protocol.call {
|
||||
env.EXPECT().Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
|
||||
Return(testCase.protocol.value, testCase.protocol.err)
|
||||
|
||||
servers := []models.IvpnServer{{Hostname: "a"}}
|
||||
allServers := models.AllServers{
|
||||
Ivpn: models.IvpnServers{
|
||||
Servers: servers,
|
||||
},
|
||||
}
|
||||
|
||||
if testCase.targetIP.call {
|
||||
env.EXPECT().Get("OPENVPN_TARGET_IP").
|
||||
Return(testCase.targetIP.value, testCase.targetIP.err)
|
||||
}
|
||||
if testCase.countries.call {
|
||||
env.EXPECT().CSVInside("COUNTRY", constants.IvpnCountryChoices()).
|
||||
env.EXPECT().CSVInside("COUNTRY", constants.IvpnCountryChoices(servers)).
|
||||
Return(testCase.countries.values, testCase.countries.err)
|
||||
}
|
||||
if testCase.cities.call {
|
||||
env.EXPECT().CSVInside("CITY", constants.IvpnCityChoices()).
|
||||
env.EXPECT().CSVInside("CITY", constants.IvpnCityChoices(servers)).
|
||||
Return(testCase.cities.values, testCase.cities.err)
|
||||
}
|
||||
if testCase.isps.call {
|
||||
env.EXPECT().CSVInside("ISP", constants.IvpnISPChoices(servers)).
|
||||
Return(testCase.isps.values, testCase.isps.err)
|
||||
}
|
||||
if testCase.hostnames.call {
|
||||
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.IvpnHostnameChoices()).
|
||||
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.IvpnHostnameChoices(servers)).
|
||||
Return(testCase.hostnames.values, testCase.hostnames.err)
|
||||
}
|
||||
if testCase.protocol.call {
|
||||
env.EXPECT().Inside("OPENVPN_PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
|
||||
Return(testCase.protocol.value, testCase.protocol.err)
|
||||
}
|
||||
if testCase.ovpnPort.getCall {
|
||||
env.EXPECT().Get("OPENVPN_PORT", gomock.Any()).
|
||||
Return(testCase.ovpnPort.getValue, testCase.ovpnPort.getErr)
|
||||
}
|
||||
if testCase.ovpnPort.portCall {
|
||||
env.EXPECT().Port("OPENVPN_PORT").
|
||||
Return(testCase.ovpnPort.portValue, testCase.ovpnPort.portErr)
|
||||
}
|
||||
if testCase.ovpnOldPort.getCall {
|
||||
env.EXPECT().Get("PORT", gomock.Any()).
|
||||
Return(testCase.ovpnOldPort.getValue, testCase.ovpnOldPort.getErr)
|
||||
}
|
||||
if testCase.ovpnOldPort.portCall {
|
||||
env.EXPECT().Port("PORT").
|
||||
Return(testCase.ovpnOldPort.portValue, testCase.ovpnOldPort.portErr)
|
||||
}
|
||||
if testCase.wgPort.getCall {
|
||||
env.EXPECT().Get("WIREGUARD_ENDPOINT_PORT", gomock.Any()).
|
||||
Return(testCase.wgPort.getValue, testCase.wgPort.getErr)
|
||||
}
|
||||
if testCase.wgPort.portCall {
|
||||
env.EXPECT().Port("WIREGUARD_ENDPOINT_PORT").
|
||||
Return(testCase.wgPort.portValue, testCase.wgPort.portErr)
|
||||
}
|
||||
if testCase.wgOldPort.getCall {
|
||||
env.EXPECT().Get("WIREGUARD_PORT", gomock.Any()).
|
||||
Return(testCase.wgOldPort.getValue, testCase.wgOldPort.getErr)
|
||||
}
|
||||
if testCase.wgOldPort.portCall {
|
||||
env.EXPECT().Port("WIREGUARD_PORT").
|
||||
Return(testCase.wgOldPort.portValue, testCase.wgOldPort.portErr)
|
||||
}
|
||||
|
||||
r := reader{env: env}
|
||||
r := reader{
|
||||
servers: allServers,
|
||||
env: env,
|
||||
}
|
||||
|
||||
var settings Provider
|
||||
err := settings.readIvpn(r)
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/openvpn/parse"
|
||||
)
|
||||
|
||||
var (
|
||||
errClientCert = errors.New("cannot read client certificate")
|
||||
errClientKey = errors.New("cannot read client key")
|
||||
)
|
||||
|
||||
func readClientKey(r reader) (clientKey string, err error) {
|
||||
@@ -13,22 +17,7 @@ func readClientKey(r reader) (clientKey string, err error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return extractClientKey(b)
|
||||
}
|
||||
|
||||
var errDecodePEMBlockClientKey = errors.New("cannot decode PEM block from client key")
|
||||
|
||||
func extractClientKey(b []byte) (key string, err error) {
|
||||
pemBlock, _ := pem.Decode(b)
|
||||
if pemBlock == nil {
|
||||
return "", errDecodePEMBlockClientKey
|
||||
}
|
||||
parsedBytes := pem.EncodeToMemory(pemBlock)
|
||||
s := string(parsedBytes)
|
||||
s = strings.ReplaceAll(s, "\n", "")
|
||||
s = strings.TrimPrefix(s, "-----BEGIN PRIVATE KEY-----")
|
||||
s = strings.TrimSuffix(s, "-----END PRIVATE KEY-----")
|
||||
return s, nil
|
||||
return parse.ExtractPrivateKey(b)
|
||||
}
|
||||
|
||||
func readClientCertificate(r reader) (clientCertificate string, err error) {
|
||||
@@ -36,20 +25,5 @@ func readClientCertificate(r reader) (clientCertificate string, err error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return extractClientCertificate(b)
|
||||
}
|
||||
|
||||
var errDecodePEMBlockClientCert = errors.New("cannot decode PEM block from client certificate")
|
||||
|
||||
func extractClientCertificate(b []byte) (certificate string, err error) {
|
||||
pemBlock, _ := pem.Decode(b)
|
||||
if pemBlock == nil {
|
||||
return "", errDecodePEMBlockClientCert
|
||||
}
|
||||
parsedBytes := pem.EncodeToMemory(pemBlock)
|
||||
s := string(parsedBytes)
|
||||
s = strings.ReplaceAll(s, "\n", "")
|
||||
s = strings.TrimPrefix(s, "-----BEGIN CERTIFICATE-----")
|
||||
s = strings.TrimSuffix(s, "-----END CERTIFICATE-----")
|
||||
return s, nil
|
||||
return parse.ExtractCert(b)
|
||||
}
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_extractClientKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
const validPEM = `
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCrQDrezCptkWxX
|
||||
ywm3KdXtvti+rPF3vfzOmXRKiKXDMpMxzoiaD5Wspirxxjr4C+B14xTwZjJZfxJL
|
||||
2HpPdOeBmA5tmAoGUESspnzxR/N1T4Uggx0vlAzFo0UZ0sutV6CJK19Kk38REwlG
|
||||
AB8gl6JYeSUuu6qREjrLVwFRH72acvC/p4jBki/MjAfEaeHc0yDJT9jpjpchw+Hx
|
||||
Ymy+1BnfNTAfGDdTVx9qWb+ByQ7xfvzuD9AOeqiWApDzZIuDDsaWn2orv+syoJVo
|
||||
rV52/F+75zks6+fzQ+0sotBlRyvsZKGi80F89RIHwG+5LNSuRDWnVvrwv1oc6V2/
|
||||
lMidwT7yb0kXt0IRW6JzbaHyB2LkPazBlr6IPNupk83x9t2Buw0HI2SQKHMKOChU
|
||||
i2/906yLUOo3QpAi3Wk1c/Xu9DvGR/pOA15WCakiAfG3Fq6hUxNncmpOMeOLF/ez
|
||||
L19jZ3KA4E2Te4+GA0NYlXgkDbsIILWapHwqHXcDukynHisr7RawjrvXoLyasm4L
|
||||
O66aNXK9wtipSMDA7tdlQP6Xe9bHflDHxwreiuEGxnrsvLU7LHBWdD7UT2/u8zdr
|
||||
pimqi4L7W5p5aOBMn8jSVCO9+4CAxiLlc2qx5vb4/EPMsdQfacYP7vY9iVh/qPi3
|
||||
bcUVGUlg8wAJDrTksxU1K3FVR7BEPwIDAQABAoICAAhyrbTJ+5nWH7MhCASqIqyM
|
||||
yqJ1Y6AVlkAW397BaPP9Lbe6SZDYDfkrZVjx/3y3EUafgivtzrQNibiGIFqFGNqS
|
||||
xrtvUadIFGsz91vrwb3aw2V8MldjhVHGoSUJ+hQ+C2RY6GWEazNLbhyu6tovwMl+
|
||||
iHAKv/pSHOZlD2KSH0dcPjYmLJ/n90Wu7r8ovgSnwalMsBWtfBUlVaMTyOuNCQ2y
|
||||
0QHnrusElD8p2EGtynftXMrdqtTcBi8IR2BKaHt5oiBSEum/mPmxZE16p/tUreBW
|
||||
IsLtjE663htimMc2QJtzx2mDeIqSiGYrfxdyd7d1E/SCXPS9a9ObS42k6FSn8NPu
|
||||
K5kN6fPV5EDM2CqKEt9QZPlyrjZIuffOZtJj0xPuTwhRle4SOtyjn2c/vsv9Fkrp
|
||||
B6B1v7T4+SSOIedOYkL+FP/IexMNG/ZTB5Y2hrZ03JW9RGpFAa4//qGG2qUCR3hE
|
||||
rVS6v58qO/3+TCFSn/TI8AfcTcJbes3yTbVyLH6NAjATfYqJDJJFf+PG0qKc8q1N
|
||||
KvXmT+x4JiBBM32cOg11GPflxIZSKi9He50hnPGnC042N06ba/pkUPG49XwE37hn
|
||||
kIGmcFGcDIMDTEZnPBogPFqGpepYdwGWxbadRiUoX2wgurHRRmA0YM32MjVky9C1
|
||||
12Q/Jy9PIk/qdjYdWfAhAoIBAQDcvxfUx7MKMFgYYm4E51X+7B9QoxdhVaxcoVgK
|
||||
VwfvedsLi0Bk1B1JVSXqnNfyDZbpxFz2v5Xd/dSit2rjnfBm+DoJYN9ZNnrbIH+s
|
||||
qsO1DuHZvMZlRDJbpt7PpVH/pcf7rEWRY+avkMMsiGwI/ruDs17eu7jULeG7N4jb
|
||||
kh1mdvF7K56O6Xe8jGJu5qaOPRWOkABK1cEOjQ5hB1iAwO/ua5hehP87SvbYzIhz
|
||||
nQTE3AqTWgWbIyC4R85U7tS9hsXnSQ/ICM9pWcyN0Y667LwR2tX0QKl5M/YoM0sG
|
||||
mw+VQED8O2R45jTzSAcox77dRg55Pp3Xexsp2iVvaTIeAaevAoIBAQDGmZS1gFO4
|
||||
TEgQXHdmibLizDUHLuw662GC+3Hilx+nZBZtWOc6t8yquUyggSKQmBDiKAf0ipMe
|
||||
xFao+5I3StJJ2P4Vel95Vcu8KgqCF736Q1iNgDHuW8ho8e0y+YE371x5co3POGC0
|
||||
SfbcnRTXQx2+wWXzZDh+KtnaDUyDN12/qCIUyAuSVLwEM28ZFM3qadG1aUdCB5oe
|
||||
o8jfgsg6YSukm4uE/tuI3/wAI7FkaCqvt/zkLauRff5FcNa7os4EKtNnGfebxscP
|
||||
yFYpMsW9VI0rfmYz02gho33lnofs4o8x/gxh6t5zfVbsZ7vUiSDJBahWboG9aE99
|
||||
OY2TKb6ibsBxAoIBAQChDBVR2oPnqg+Lcrw7fZ8Cxbeu992F2KBQUDHQEWCruSYy
|
||||
zNwk84+OQb3Q5a6yXHG+iNEd//ZRp+8q60/jUgXiybRlxTQNfS6ykYo0Kb1wabQi
|
||||
S5Qeq1tl/F9P9JfXQFafaTaz9MOHUMDjy3+uLFIXqpRLQX995R9rm/+P2ZDzgVF5
|
||||
///E2dXOTElACax3117TzIE6F6qqeASGi3ppLNmfAwZ95t/inTVsRARE/MhO6w4Y
|
||||
JLQ0U7N6XoDM/BVfVGUr8OS/lpXjkW0oBjvwaehnylUPxuEdmOg8ufdBkX0T8XW3
|
||||
z4jkn2cAGouGl/vKqWLD2AgF/j16Ejn/hyrWM3TnAoIBAA6lSssrwIDJ11KljwSX
|
||||
yQJirtJtymv56cIACwD7xhDRF7pOoRa6cTRx383CWCszm6Mh8pw9D+Zn8kAZ9Ulw
|
||||
khtyDiLFWH8ZLaIds5Kub4siJkihGI2MZTYgCS8GKVpXo4ktQnnynWcOQU85okzR
|
||||
nULw/jS5wlTDkjc7XdYbYiV9H65KplfPOeJRbLL7zsensBhhwCiFaP8zct/QxDVR
|
||||
7yb/dYWESepJIktcVnuiFuvIdLTbDVj4YqT6UkuaEPlLszVaO+FYAlwOmRQGs4Bn
|
||||
2NVJR/4wa/B3HxSs4Tc96fN02bLq4CbCKoPajoZ46lsIuMZO9fBi3eHNObyNiopu
|
||||
AnECggEBAJiJ0tK/PGh+Q9uv57Z4QcmbawoxMQW1qK/rLYwacYsSpzo8VhbZf+Jh
|
||||
8biMg9AIQsLWnqmB3gmndePArGXkSxnilRozNLaeclTZy7rh00BctTEfgee4Kxdi
|
||||
JKkJlVK0CE8I6txVRqkoOMyxsk1kRZ4l2yW2nxzyWlJKwvD75x2PQ6xWvpLAggyn
|
||||
q00I3MzNIgR123jytN1NyC7l+mnGoC23ToXM7B3/PQjGYTq3jawKomrX1cmwzKBT
|
||||
+pzjtJSWvMeUEZQS1PpOhxpPBRHagdKXt+ug2DqDtU6rfpDGtTBh5QNkg5SA7lxZ
|
||||
zZjrL52saevO25cigVl+hxcnY8DTpbk=
|
||||
-----END PRIVATE KEY-----
|
||||
`
|
||||
const validKeyString = "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" //nolint:lll
|
||||
testCases := map[string]struct {
|
||||
b []byte
|
||||
key string
|
||||
err error
|
||||
}{
|
||||
"no input": {
|
||||
err: errDecodePEMBlockClientKey,
|
||||
},
|
||||
"bad input": {
|
||||
b: []byte{1, 2, 3},
|
||||
err: errDecodePEMBlockClientKey,
|
||||
},
|
||||
"valid key": {
|
||||
b: []byte(validPEM),
|
||||
key: validKeyString,
|
||||
},
|
||||
}
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
key, err := extractClientKey(testCase.b)
|
||||
if testCase.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, testCase.err.Error(), err.Error())
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, testCase.key, key)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_extractClientCertificate(t *testing.T) {
|
||||
t.Parallel()
|
||||
const validPEM = `
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGrDCCBJSgAwIBAgIEAdTnfTANBgkqhkiG9w0BAQsFADB7MQswCQYDVQQGEwJS
|
||||
TzESMBAGA1UEBxMJQnVjaGFyZXN0MRgwFgYDVQQKEw9DeWJlckdob3N0IFMuQS4x
|
||||
GzAZBgNVBAMTEkN5YmVyR2hvc3QgUm9vdCBDQTEhMB8GCSqGSIb3DQEJARYSaW5m
|
||||
b0BjeWJlcmdob3N0LnJvMB4XDTIwMDcwNDE1MjkzNloXDTMwMDcwMjE1MjkzNlow
|
||||
fTELMAkGA1UEBhMCUk8xEjAQBgNVBAcMCUJ1Y2hhcmVzdDEYMBYGA1UECgwPQ3li
|
||||
ZXJHaG9zdCBTLkEuMR0wGwYDVQQDDBRjLmoua2xhdmVyQGdtYWlsLmNvbTEhMB8G
|
||||
CSqGSIb3DQEJARYSaW5mb0BjeWJlcmdob3N0LnJvMIICIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAg8AMIICCgKCAgEAobp2NlGUHMNBe08YEOnVG3QJjF3ZaXbRhE/II9rmtgJT
|
||||
NZtDohGChvFlNRsExKzVrKxHCeuJkVffwzQ6fYk4/M1RdYLJUh0UVw3e4WdApw8E
|
||||
7TJZxDYm4SHQNXUvt1Rt5TjslcXxIpDZgrMSc/kHROYEL9tdgdzPZErUJehXyJPh
|
||||
EzIrzmAJh501x7WwKPz9ctSVlItyavqEWFF2vyUa6X9DYmD9mQTz5c+VXNO5DkXm
|
||||
PFBIaEVDnvFtcjGJ56yEvFnWVukL+OUX7ezowrIOFOcp9udjgpeiHq+XvsQ6ER0D
|
||||
Jt25MiEId3NjkxtZ8BitDftTcLN/kt81hWKT7adMVc3kpIZ80cxrwRCttMd7sHAz
|
||||
KI9u7pMxv10eUOsIEY87ewBe3l6KvEnjA+9uIjim6gLLebDIaEH50Ee9PzNJ8fqQ
|
||||
2u54Ab4bt00/H1sUnJ6Ss/+WsQDOK1BsPRKKcnHZntOlHrs2Tu5+txKNU2cOapI8
|
||||
SjVULUNKrRXASbpfWnLUfri/HO742bJb/TjkOJcOxta3hTPFAhaRWBusVlB41XVH
|
||||
euH5DAhugYXeSNK6/6Ul8YvKUNH/7QbxuGIGXfth19Xl4QLI1umyEjZopSlt3tOi
|
||||
O2V1soVNSQCCfxXVoCTMESMLjhkjWdmBDhdy2GTW7S4YoJfqVKiS18rYkN7I4ZMC
|
||||
AwEAAaOCATQwggEwMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMDQGCWCGSAGG+EIB
|
||||
DQQnFiVDeWJlckdob3N0IEdlbmVyYXRlZCBVc2VyIENlcnRpZmljYXRlMBEGCWCG
|
||||
SAGG+EIBAQQEAwIHgDAdBgNVHQ4EFgQULwUtU5s6pL2NN9gPeEnKX0dhwiswga0G
|
||||
A1UdIwSBpTCBooAU6tdK1g/He5qzjeAoM5eHt4in9iWhf6R9MHsxCzAJBgNVBAYT
|
||||
AlJPMRIwEAYDVQQHEwlCdWNoYXJlc3QxGDAWBgNVBAoTD0N5YmVyR2hvc3QgUy5B
|
||||
LjEbMBkGA1UEAxMSQ3liZXJHaG9zdCBSb290IENBMSEwHwYJKoZIhvcNAQkBFhJp
|
||||
bmZvQGN5YmVyZ2hvc3Qucm+CCQCcVButZsQ0uzANBgkqhkiG9w0BAQsFAAOCAgEA
|
||||
ystGIMYhQWaEdTqlnLCytrr8657t+PuidZMNNIaPB3wN2Fi2xKf14DTg03mqxjmP
|
||||
Pb+f+PVNIOV5PdWD4jcQwOP1GEboGV0DFzlRGeAtDcvKwdee4oASJbZq1CETqDao
|
||||
hQTxKEWC+UBk2F36nOaEI6Sab+Mb4cR9//PAwvzOqrXuGF5NuIOX7eFtCMQSgQq6
|
||||
lRRqTQjekm0Dxigx4JA92Jo2qZRwCJ0T3IXBJGL831HCFJbDWv8PV3lsfFb/i2+v
|
||||
r54uywFQVWWp18dYi97gipfuQ4zRg2Ldx5aXSmnhhKpg5ioZvtk043QofF12YORh
|
||||
obElqavRbvvhZvlCouvcuoq9QKi7IPe5SJZkZ1X7ezMesCwBzwFpt6vRUAcslsNF
|
||||
bcYS1iSENlY/PTcDqBhbKuc9yAhq+/aUgaY/8VF5RWVzSRZufbf3BPwOkE4K0Uyb
|
||||
aobO/YX0JOkCacAD+4tdR6YSXNIMMRAOCBQvxbxFXaHzhwhzBAjdsC56FrJKwXvQ
|
||||
rRLU3tF4P0zFMeNTay8uTtUXugDK7EnklLESuYdpUJ8bUMlAUhJBi6UFI9/icMud
|
||||
xXvLRvhnBW9EtKib5JnVFUovcEUt+3EJbyst05nkL4YPjQS4TC9DHdo5SyRAy1Tp
|
||||
iOCYTbretAFZRhh6ycUN5hBeN8GMQxiMreMtDV4PEIQ=
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
const validCertificateString = "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" //nolint:lll
|
||||
testCases := map[string]struct {
|
||||
b []byte
|
||||
certificate string
|
||||
err error
|
||||
}{
|
||||
"no input": {
|
||||
err: errDecodePEMBlockClientCert,
|
||||
},
|
||||
"bad input": {
|
||||
b: []byte{1, 2, 3},
|
||||
err: errDecodePEMBlockClientCert,
|
||||
},
|
||||
"valid key": {
|
||||
b: []byte(validPEM),
|
||||
certificate: validCertificateString,
|
||||
},
|
||||
}
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
certificate, err := extractClientCertificate(testCase.b)
|
||||
if testCase.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, testCase.err.Error(), err.Error())
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, testCase.certificate, certificate)
|
||||
})
|
||||
}
|
||||
}
|
||||
30
internal/configuration/log.go
Normal file
30
internal/configuration/log.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
type Log struct {
|
||||
Level logging.Level `json:"level"`
|
||||
}
|
||||
|
||||
func (settings *Log) lines() (lines []string) {
|
||||
lines = append(lines, lastIndent+"Log:")
|
||||
|
||||
lines = append(lines, indent+lastIndent+"Level: "+settings.Level.String())
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
func (settings *Log) read(env params.Interface) (err error) {
|
||||
defaultLevel := logging.LevelInfo.String()
|
||||
settings.Level, err = env.LogLevel("LOG_LEVEL", params.Default(defaultLevel))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable LOG_LEVEL: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -9,28 +9,29 @@ import (
|
||||
|
||||
func (settings *Provider) readMullvad(r reader) (err error) {
|
||||
settings.Name = constants.Mullvad
|
||||
servers := r.servers.GetMullvad()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.MullvadCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.MullvadCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.MullvadCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.MullvadCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.MullvadHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.MullvadHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.ISPs, err = r.env.CSVInside("ISP", constants.MullvadISPChoices())
|
||||
settings.ServerSelection.ISPs, err = r.env.CSVInside("ISP", constants.MullvadISPChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable ISP: %w", err)
|
||||
}
|
||||
@@ -40,17 +41,34 @@ func (settings *Provider) readMullvad(r reader) (err error) {
|
||||
return fmt.Errorf("environment variable OWNED: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readMullvad(r.env)
|
||||
}
|
||||
|
||||
func (settings *OpenVPNSelection) readMullvad(env params.Interface) (err error) {
|
||||
settings.TCP, err = readProtocol(env)
|
||||
err = settings.ServerSelection.OpenVPN.readMullvad(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.CustomPort, err = readOpenVPNCustomPort(env, settings.TCP,
|
||||
[]uint16{80, 443, 1401}, []uint16{53, 1194, 1195, 1196, 1197, 1300, 1301, 1302, 1303, 1400})
|
||||
return settings.ServerSelection.Wireguard.readMullvad(r.env)
|
||||
}
|
||||
|
||||
func (settings *OpenVPNSelection) readMullvad(r reader) (err error) {
|
||||
settings.TCP, err = readOpenVPNProtocol(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.CustomPort, err = readOpenVPNCustomPort(r, openvpnPortValidation{
|
||||
tcp: settings.TCP,
|
||||
allowedTCP: []uint16{80, 443, 1401},
|
||||
allowedUDP: []uint16{53, 1194, 1195, 1196, 1197, 1300, 1301, 1302, 1303, 1400},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (settings *WireguardSelection) readMullvad(env params.Interface) (err error) {
|
||||
settings.EndpointPort, err = readWireguardCustomPort(env, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -10,33 +10,29 @@ import (
|
||||
|
||||
func (settings *Provider) readNordvpn(r reader) (err error) {
|
||||
settings.Name = constants.Nordvpn
|
||||
servers := r.servers.GetNordvpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.NordvpnRegionChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.NordvpnRegionChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.NordvpnHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.NordvpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Names, err = r.env.CSVInside("SERVER_NAME", constants.NordvpnHostnameChoices())
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_NAME: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Numbers, err = readNordVPNServerNumbers(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r)
|
||||
}
|
||||
|
||||
func readNordVPNServerNumbers(env params.Interface) (numbers []uint16, err error) {
|
||||
|
||||
@@ -19,9 +19,9 @@ type OpenVPN struct {
|
||||
Flags []string `json:"flags"`
|
||||
MSSFix uint16 `json:"mssfix"`
|
||||
Root bool `json:"run_as_root"`
|
||||
Cipher string `json:"cipher"`
|
||||
Ciphers []string `json:"ciphers"`
|
||||
Auth string `json:"auth"`
|
||||
Config string `json:"custom_config"`
|
||||
ConfFile string `json:"conf_file"`
|
||||
Version string `json:"version"`
|
||||
ClientCrt string `json:"-"` // Cyberghost
|
||||
ClientKey string `json:"-"` // Cyberghost, VPNUnlimited
|
||||
@@ -52,15 +52,15 @@ func (settings *OpenVPN) lines() (lines []string) {
|
||||
lines = append(lines, indent+lastIndent+"Run as root: enabled")
|
||||
}
|
||||
|
||||
if len(settings.Cipher) > 0 {
|
||||
lines = append(lines, indent+lastIndent+"Custom cipher: "+settings.Cipher)
|
||||
if len(settings.Ciphers) > 0 {
|
||||
lines = append(lines, indent+lastIndent+"Custom ciphers: "+commaJoin(settings.Ciphers))
|
||||
}
|
||||
if len(settings.Auth) > 0 {
|
||||
lines = append(lines, indent+lastIndent+"Custom auth algorithm: "+settings.Auth)
|
||||
}
|
||||
|
||||
if len(settings.Config) > 0 {
|
||||
lines = append(lines, indent+lastIndent+"Custom configuration: "+settings.Config)
|
||||
if settings.ConfFile != "" {
|
||||
lines = append(lines, indent+lastIndent+"Configuration file: "+settings.ConfFile)
|
||||
}
|
||||
|
||||
if settings.ClientKey != "" {
|
||||
@@ -83,13 +83,14 @@ func (settings *OpenVPN) lines() (lines []string) {
|
||||
}
|
||||
|
||||
func (settings *OpenVPN) read(r reader, serviceProvider string) (err error) {
|
||||
settings.Config, err = r.env.Get("OPENVPN_CUSTOM_CONFIG", params.CaseSensitiveValue())
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable OPENVPN_CUSTOM_CONFIG: %w", err)
|
||||
credentialsRequired := false
|
||||
switch serviceProvider {
|
||||
case constants.Custom:
|
||||
case constants.VPNUnlimited:
|
||||
default:
|
||||
credentialsRequired = true
|
||||
}
|
||||
|
||||
credentialsRequired := settings.Config == "" && serviceProvider != constants.VPNUnlimited
|
||||
|
||||
settings.User, err = r.getFromEnvOrSecretFile("OPENVPN_USER", credentialsRequired, []string{"USER"})
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable OPENVPN_USER: %w", err)
|
||||
@@ -126,12 +127,12 @@ func (settings *OpenVPN) read(r reader, serviceProvider string) (err error) {
|
||||
settings.Flags = strings.Fields(flagsStr)
|
||||
}
|
||||
|
||||
settings.Root, err = r.env.YesNo("OPENVPN_ROOT", params.Default("yes"))
|
||||
settings.Root, err = r.env.YesNo("OPENVPN_ROOT", params.Default("no"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable OPENVPN_ROOT: %w", err)
|
||||
}
|
||||
|
||||
settings.Cipher, err = r.env.Get("OPENVPN_CIPHER")
|
||||
settings.Ciphers, err = r.env.CSV("OPENVPN_CIPHER")
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable OPENVPN_CIPHER: %w", err)
|
||||
}
|
||||
@@ -158,16 +159,17 @@ func (settings *OpenVPN) read(r reader, serviceProvider string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.EncPreset, err = getPIAEncryptionPreset(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch serviceProvider {
|
||||
case constants.Custom:
|
||||
err = settings.readCustom(r) // read OPENVPN_CUSTOM_CONFIG
|
||||
case constants.Cyberghost:
|
||||
err = settings.readCyberghost(r)
|
||||
case constants.PrivateInternetAccess:
|
||||
settings.EncPreset, err = getPIAEncryptionPreset(r)
|
||||
case constants.VPNUnlimited:
|
||||
err = settings.readVPNUnlimited(r)
|
||||
case constants.Wevpn:
|
||||
err = settings.readWevpn(r)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -176,10 +178,11 @@ func (settings *OpenVPN) read(r reader, serviceProvider string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func readProtocol(env params.Interface) (tcp bool, err error) {
|
||||
protocol, err := env.Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, params.Default(constants.UDP))
|
||||
func readOpenVPNProtocol(r reader) (tcp bool, err error) {
|
||||
protocol, err := r.env.Inside("OPENVPN_PROTOCOL", []string{constants.TCP, constants.UDP},
|
||||
params.Default(constants.UDP), params.RetroKeys([]string{"PROTOCOL"}, r.onRetroActive))
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("environment variable PROTOCOL: %w", err)
|
||||
return false, fmt.Errorf("environment variable OPENVPN_PROTOCOL: %w", err)
|
||||
}
|
||||
return protocol == constants.TCP, nil
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@ import (
|
||||
func Test_OpenVPN_JSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
in := OpenVPN{
|
||||
Root: true,
|
||||
Flags: []string{},
|
||||
Root: true,
|
||||
Flags: []string{},
|
||||
Ciphers: []string{},
|
||||
}
|
||||
data, err := json.MarshalIndent(in, "", " ")
|
||||
require.NoError(t, err)
|
||||
@@ -23,9 +24,9 @@ func Test_OpenVPN_JSON(t *testing.T) {
|
||||
"flags": [],
|
||||
"mssfix": 0,
|
||||
"run_as_root": true,
|
||||
"cipher": "",
|
||||
"ciphers": [],
|
||||
"auth": "",
|
||||
"custom_config": "",
|
||||
"conf_file": "",
|
||||
"version": "",
|
||||
"encryption_preset": "",
|
||||
"ipv6": false,
|
||||
|
||||
43
internal/configuration/perfectprivacy.go
Normal file
43
internal/configuration/perfectprivacy.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
)
|
||||
|
||||
func (settings *Provider) readPerfectPrivacy(r reader) (err error) {
|
||||
settings.Name = constants.Perfectprivacy
|
||||
servers := r.servers.GetPerfectprivacy()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PerfectprivacyCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readPerfectPrivacy(r)
|
||||
}
|
||||
|
||||
func (settings *OpenVPNSelection) readPerfectPrivacy(r reader) (err error) {
|
||||
settings.TCP, err = readOpenVPNProtocol(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
portValidation := openvpnPortValidation{
|
||||
tcp: settings.TCP,
|
||||
allowedTCP: []uint16{44, 443, 4433},
|
||||
allowedUDP: []uint16{44, 443, 4433},
|
||||
}
|
||||
settings.CustomPort, err = readOpenVPNCustomPort(r, portValidation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -8,28 +8,29 @@ import (
|
||||
|
||||
func (settings *Provider) readPrivado(r reader) (err error) {
|
||||
settings.Name = constants.Privado
|
||||
servers := r.servers.GetPrivado()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PrivadoCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PrivadoCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PrivadoRegionChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PrivadoRegionChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PrivadoCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PrivadoCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PrivadoHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PrivadoHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
@@ -9,23 +9,24 @@ import (
|
||||
|
||||
func (settings *Provider) readPrivateInternetAccess(r reader) (err error) {
|
||||
settings.Name = constants.PrivateInternetAccess
|
||||
servers := r.servers.GetPia()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PIAGeoChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PIAGeoChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PIAHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PIAHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_NAME", constants.PIANameChoices())
|
||||
settings.ServerSelection.Names, err = r.env.CSVInside("SERVER_NAME", constants.PIANameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_NAME: %w", err)
|
||||
}
|
||||
@@ -52,9 +53,9 @@ func (settings *OpenVPNSelection) readPrivateInternetAccess(r reader) (err error
|
||||
return err
|
||||
}
|
||||
|
||||
settings.CustomPort, err = readPortOrZero(r.env, "PORT")
|
||||
settings.CustomPort, err = readOpenVPNCustomPort(r, openvpnPortValidation{allAllowed: true})
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable PORT: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -64,7 +65,7 @@ func getPIAEncryptionPreset(r reader) (encryptionPreset string, err error) {
|
||||
encryptionPreset, err = r.env.Inside("PIA_ENCRYPTION",
|
||||
[]string{constants.PIAEncryptionPresetNone, constants.PIAEncryptionPresetNormal, constants.PIAEncryptionPresetStrong},
|
||||
params.RetroKeys([]string{"ENCRYPTION"}, r.onRetroActive),
|
||||
params.Default(constants.PIACertificateStrong),
|
||||
params.Default(constants.PIAEncryptionPresetStrong),
|
||||
)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("environment variable PIA_ENCRYPTION: %w", err)
|
||||
|
||||
@@ -8,26 +8,28 @@ import (
|
||||
|
||||
func (settings *Provider) readPrivatevpn(r reader) (err error) {
|
||||
settings.Name = constants.Privatevpn
|
||||
servers := r.servers.GetPrivatevpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PrivatevpnCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PrivatevpnCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PrivatevpnCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PrivatevpnCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PrivatevpnHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.PrivatevpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r.env)
|
||||
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r)
|
||||
}
|
||||
|
||||
@@ -9,33 +9,35 @@ import (
|
||||
|
||||
func (settings *Provider) readProtonvpn(r reader) (err error) {
|
||||
settings.Name = constants.Protonvpn
|
||||
servers := r.servers.GetProtonvpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.ProtonvpnCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.ProtonvpnCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.ProtonvpnRegionChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.ProtonvpnRegionChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.ProtonvpnCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.ProtonvpnCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Names, err = r.env.CSVInside("SERVER_NAME", constants.ProtonvpnNameChoices())
|
||||
settings.ServerSelection.Names, err = r.env.CSVInside("SERVER_NAME", constants.ProtonvpnNameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_NAME: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.ProtonvpnHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.ProtonvpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
@@ -45,5 +47,5 @@ func (settings *Provider) readProtonvpn(r reader) (err error) {
|
||||
return fmt.Errorf("environment variable FREE_ONLY: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r.env)
|
||||
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r)
|
||||
}
|
||||
|
||||
@@ -49,8 +49,12 @@ func (settings *Provider) read(r reader, vpnType string) error {
|
||||
}
|
||||
|
||||
switch settings.Name {
|
||||
case constants.Custom:
|
||||
err = settings.readCustom(r, vpnType)
|
||||
case constants.Cyberghost:
|
||||
err = settings.readCyberghost(r)
|
||||
case constants.Expressvpn:
|
||||
err = settings.readExpressvpn(r)
|
||||
case constants.Fastestvpn:
|
||||
err = settings.readFastestvpn(r)
|
||||
case constants.HideMyAss:
|
||||
@@ -63,6 +67,8 @@ func (settings *Provider) read(r reader, vpnType string) error {
|
||||
err = settings.readMullvad(r)
|
||||
case constants.Nordvpn:
|
||||
err = settings.readNordvpn(r)
|
||||
case constants.Perfectprivacy:
|
||||
err = settings.readPerfectPrivacy(r)
|
||||
case constants.Privado:
|
||||
err = settings.readPrivado(r)
|
||||
case constants.PrivateInternetAccess:
|
||||
@@ -81,6 +87,8 @@ func (settings *Provider) read(r reader, vpnType string) error {
|
||||
err = settings.readVPNUnlimited(r)
|
||||
case constants.Vyprvpn:
|
||||
err = settings.readVyprvpn(r)
|
||||
case constants.Wevpn:
|
||||
err = settings.readWevpn(r)
|
||||
case constants.Windscribe:
|
||||
err = settings.readWindscribe(r)
|
||||
default:
|
||||
@@ -99,11 +107,17 @@ func (settings *Provider) readVPNServiceProvider(r reader, vpnType string) (err
|
||||
switch vpnType {
|
||||
case constants.OpenVPN:
|
||||
allowedVPNServiceProviders = []string{
|
||||
"cyberghost", "fastestvpn", "hidemyass", "ipvanish", "ivpn", "mullvad", "nordvpn",
|
||||
"privado", "pia", "private internet access", "privatevpn", "protonvpn",
|
||||
"purevpn", "surfshark", "torguard", constants.VPNUnlimited, "vyprvpn", "windscribe"}
|
||||
constants.Custom,
|
||||
"cyberghost", constants.Expressvpn, "fastestvpn", "hidemyass", "ipvanish",
|
||||
"ivpn", "mullvad", "nordvpn",
|
||||
constants.Perfectprivacy, "privado", "pia", "private internet access", "privatevpn", "protonvpn",
|
||||
"purevpn", "surfshark", "torguard", constants.VPNUnlimited, "vyprvpn",
|
||||
constants.Wevpn, "windscribe"}
|
||||
case constants.Wireguard:
|
||||
allowedVPNServiceProviders = []string{constants.Mullvad, constants.Windscribe}
|
||||
allowedVPNServiceProviders = []string{
|
||||
constants.Custom, constants.Ivpn,
|
||||
constants.Mullvad, constants.Windscribe,
|
||||
}
|
||||
}
|
||||
|
||||
vpnsp, err := r.env.Inside("VPNSP", allowedVPNServiceProviders,
|
||||
@@ -114,6 +128,11 @@ func (settings *Provider) readVPNServiceProvider(r reader, vpnType string) (err
|
||||
if vpnsp == "pia" { // retro compatibility
|
||||
vpnsp = "private internet access"
|
||||
}
|
||||
|
||||
if settings.isOpenVPNCustomConfig(r.env) { // retro compatibility
|
||||
vpnsp = constants.Custom
|
||||
}
|
||||
|
||||
settings.Name = vpnsp
|
||||
|
||||
return nil
|
||||
@@ -138,41 +157,66 @@ func readTargetIP(env params.Interface) (targetIP net.IP, err error) {
|
||||
return targetIP, nil
|
||||
}
|
||||
|
||||
func readOpenVPNCustomPort(env params.Interface, tcp bool,
|
||||
allowedTCP, allowedUDP []uint16) (port uint16, err error) {
|
||||
port, err = readPortOrZero(env, "PORT")
|
||||
type openvpnPortValidation struct {
|
||||
allAllowed bool
|
||||
tcp bool
|
||||
allowedTCP []uint16
|
||||
allowedUDP []uint16
|
||||
}
|
||||
|
||||
func readOpenVPNCustomPort(r reader, validation openvpnPortValidation) (
|
||||
port uint16, err error) {
|
||||
port, err = readPortOrZero(r.env, "OPENVPN_PORT")
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("environment variable PORT: %w", err)
|
||||
return 0, fmt.Errorf("environment variable OPENVPN_PORT: %w", err)
|
||||
} else if port == 0 {
|
||||
return 0, nil
|
||||
// Try using old variable name
|
||||
port, err = readPortOrZero(r.env, "PORT")
|
||||
if err != nil {
|
||||
r.onRetroActive("PORT", "OPENVPN_PORT")
|
||||
return 0, fmt.Errorf("environment variable PORT: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if tcp {
|
||||
for i := range allowedTCP {
|
||||
if allowedTCP[i] == port {
|
||||
if port == 0 || validation.allAllowed {
|
||||
return port, nil
|
||||
}
|
||||
|
||||
if validation.tcp {
|
||||
for _, allowedPort := range validation.allowedTCP {
|
||||
if port == allowedPort {
|
||||
return port, nil
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf(
|
||||
"environment variable PORT: %w: port %d for TCP protocol, can only be one of %s",
|
||||
ErrInvalidPort, port, portsToString(allowedTCP))
|
||||
ErrInvalidPort, port, portsToString(validation.allowedTCP))
|
||||
}
|
||||
for i := range allowedUDP {
|
||||
if allowedUDP[i] == port {
|
||||
for _, allowedPort := range validation.allowedUDP {
|
||||
if port == allowedPort {
|
||||
return port, nil
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf(
|
||||
"environment variable PORT: %w: port %d for UDP protocol, can only be one of %s",
|
||||
ErrInvalidPort, port, portsToString(allowedUDP))
|
||||
ErrInvalidPort, port, portsToString(validation.allowedUDP))
|
||||
}
|
||||
|
||||
// note: set allowed to an empty slice to allow all valid ports
|
||||
func readWireguardCustomPort(env params.Interface, allowed []uint16) (port uint16, err error) {
|
||||
port, err = readPortOrZero(env, "WIREGUARD_PORT")
|
||||
port, err = readPortOrZero(env, "WIREGUARD_ENDPOINT_PORT")
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("environment variable WIREGUARD_PORT: %w", err)
|
||||
return 0, fmt.Errorf("environment variable WIREGUARD_ENDPOINT_PORT: %w", err)
|
||||
} else if port == 0 {
|
||||
return 0, nil
|
||||
port, _ = readPortOrZero(env, "WIREGUARD_PORT")
|
||||
if err == nil {
|
||||
return port, nil // 0 or WIREGUARD_PORT value
|
||||
}
|
||||
return 0, nil // default 0
|
||||
}
|
||||
|
||||
if len(allowed) == 0 {
|
||||
return port, nil
|
||||
}
|
||||
|
||||
for i := range allowed {
|
||||
@@ -180,6 +224,7 @@ func readWireguardCustomPort(env params.Interface, allowed []uint16) (port uint1
|
||||
return port, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf(
|
||||
"environment variable WIREGUARD_PORT: %w: port %d, can only be one of %s",
|
||||
ErrInvalidPort, port, portsToString(allowed))
|
||||
@@ -192,3 +237,12 @@ func portsToString(ports []uint16) string {
|
||||
}
|
||||
return strings.Join(slice, ", ")
|
||||
}
|
||||
|
||||
// isOpenVPNCustomConfig is for retro compatibility to set VPNSP=custom
|
||||
// if OPENVPN_CUSTOM_CONFIG is set.
|
||||
func (settings Provider) isOpenVPNCustomConfig(env params.Interface) (ok bool) {
|
||||
s, _ := env.Get("VPN_TYPE")
|
||||
isOpenVPN := s == constants.OpenVPN
|
||||
s, _ = env.Get("OPENVPN_CUSTOM_CONFIG")
|
||||
return isOpenVPN && s != ""
|
||||
}
|
||||
|
||||
@@ -24,15 +24,32 @@ func Test_Provider_lines(t *testing.T) {
|
||||
settings: Provider{
|
||||
Name: constants.Cyberghost,
|
||||
ServerSelection: ServerSelection{
|
||||
VPN: constants.OpenVPN,
|
||||
Groups: []string{"group"},
|
||||
Regions: []string{"a", "El country"},
|
||||
VPN: constants.OpenVPN,
|
||||
Countries: []string{"a", "El country"},
|
||||
},
|
||||
},
|
||||
lines: []string{
|
||||
"|--Cyberghost settings:",
|
||||
" |--Server groups: group",
|
||||
" |--Regions: a, El country",
|
||||
" |--Countries: a, El country",
|
||||
" |--OpenVPN selection:",
|
||||
" |--Protocol: udp",
|
||||
},
|
||||
},
|
||||
"expressvpn": {
|
||||
settings: Provider{
|
||||
Name: constants.Expressvpn,
|
||||
ServerSelection: ServerSelection{
|
||||
VPN: constants.OpenVPN,
|
||||
Hostnames: []string{"a", "b"},
|
||||
Countries: []string{"c", "d"},
|
||||
Cities: []string{"e", "f"},
|
||||
},
|
||||
},
|
||||
lines: []string{
|
||||
"|--Expressvpn settings:",
|
||||
" |--Countries: c, d",
|
||||
" |--Cities: e, f",
|
||||
" |--Hostnames: a, b",
|
||||
" |--OpenVPN selection:",
|
||||
" |--Protocol: udp",
|
||||
},
|
||||
@@ -151,6 +168,21 @@ func Test_Provider_lines(t *testing.T) {
|
||||
" |--Protocol: udp",
|
||||
},
|
||||
},
|
||||
"perfectprivacy": {
|
||||
settings: Provider{
|
||||
Name: constants.Perfectprivacy,
|
||||
ServerSelection: ServerSelection{
|
||||
VPN: constants.OpenVPN,
|
||||
Cities: []string{"a", "b"},
|
||||
},
|
||||
},
|
||||
lines: []string{
|
||||
"|--Perfect Privacy settings:",
|
||||
" |--Cities: a, b",
|
||||
" |--OpenVPN selection:",
|
||||
" |--Protocol: udp",
|
||||
},
|
||||
},
|
||||
"privado": {
|
||||
settings: Provider{
|
||||
Name: constants.Privado,
|
||||
@@ -324,6 +356,27 @@ func Test_Provider_lines(t *testing.T) {
|
||||
" |--Protocol: udp",
|
||||
},
|
||||
},
|
||||
"wevpn": {
|
||||
settings: Provider{
|
||||
Name: constants.Wevpn,
|
||||
ServerSelection: ServerSelection{
|
||||
VPN: constants.OpenVPN,
|
||||
Cities: []string{"a", "b"},
|
||||
Hostnames: []string{"c", "d"},
|
||||
OpenVPN: OpenVPNSelection{
|
||||
CustomPort: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
lines: []string{
|
||||
"|--Wevpn settings:",
|
||||
" |--Cities: a, b",
|
||||
" |--Hostnames: c, d",
|
||||
" |--OpenVPN selection:",
|
||||
" |--Protocol: udp",
|
||||
" |--Custom port: 1",
|
||||
},
|
||||
},
|
||||
"windscribe": {
|
||||
settings: Provider{
|
||||
Name: constants.Windscribe,
|
||||
@@ -372,7 +425,7 @@ func Test_readProtocol(t *testing.T) {
|
||||
}{
|
||||
"error": {
|
||||
mockErr: errDummy,
|
||||
err: errors.New("environment variable PROTOCOL: dummy"),
|
||||
err: errors.New("environment variable OPENVPN_PROTOCOL: dummy"),
|
||||
},
|
||||
"success": {
|
||||
mockStr: "tcp",
|
||||
@@ -388,10 +441,13 @@ func Test_readProtocol(t *testing.T) {
|
||||
|
||||
env := mock_params.NewMockInterface(ctrl)
|
||||
env.EXPECT().
|
||||
Inside("PROTOCOL", []string{"tcp", "udp"}, gomock.Any()).
|
||||
Inside("OPENVPN_PROTOCOL", []string{"tcp", "udp"}, gomock.Any(), gomock.Any()).
|
||||
Return(testCase.mockStr, testCase.mockErr)
|
||||
reader := reader{
|
||||
env: env,
|
||||
}
|
||||
|
||||
tcp, err := readProtocol(env)
|
||||
tcp, err := readOpenVPNProtocol(reader)
|
||||
|
||||
if testCase.err != nil {
|
||||
require.Error(t, err)
|
||||
|
||||
@@ -8,31 +8,32 @@ import (
|
||||
|
||||
func (settings *Provider) readPurevpn(r reader) (err error) {
|
||||
settings.Name = constants.Purevpn
|
||||
servers := r.servers.GetPurevpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PurevpnRegionChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PurevpnRegionChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PurevpnCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PurevpnCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PurevpnCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PurevpnCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PurevpnHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PurevpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r)
|
||||
}
|
||||
|
||||
@@ -7,27 +7,39 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
ovpnextract "github.com/qdm12/gluetun/internal/openvpn/extract"
|
||||
"github.com/qdm12/golibs/params"
|
||||
"github.com/qdm12/golibs/verification"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination=warner_mock_test.go -package configuration . Warner
|
||||
|
||||
type reader struct {
|
||||
env params.Interface
|
||||
logger logging.Logger
|
||||
regex verification.Regex
|
||||
servers models.AllServers
|
||||
env params.Interface
|
||||
warner Warner
|
||||
regex verification.Regex
|
||||
ovpnExt ovpnextract.Interface
|
||||
}
|
||||
|
||||
func newReader(env params.Interface, logger logging.Logger) reader {
|
||||
type Warner interface {
|
||||
Warn(s string)
|
||||
}
|
||||
|
||||
func newReader(env params.Interface,
|
||||
servers models.AllServers, warner Warner) reader {
|
||||
return reader{
|
||||
env: env,
|
||||
logger: logger,
|
||||
regex: verification.NewRegex(),
|
||||
servers: servers,
|
||||
env: env,
|
||||
warner: warner,
|
||||
regex: verification.NewRegex(),
|
||||
ovpnExt: ovpnextract.New(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *reader) onRetroActive(oldKey, newKey string) {
|
||||
r.logger.Warn(
|
||||
r.warner.Warn(
|
||||
"You are using the old environment variable " + oldKey +
|
||||
", please consider changing it to " + newKey)
|
||||
}
|
||||
|
||||
@@ -51,22 +51,22 @@ func (r *reader) getFromEnvOrSecretFile(envKey string, compulsory bool, retroKey
|
||||
file, fileErr := os.OpenFile(filepath, os.O_RDONLY, 0)
|
||||
if os.IsNotExist(fileErr) {
|
||||
if compulsory {
|
||||
return "", envErr
|
||||
return "", fmt.Errorf("environment variable %s: %w", envKey, envErr)
|
||||
}
|
||||
return "", nil
|
||||
} else if fileErr != nil {
|
||||
return "", fmt.Errorf("%w: %s", ErrReadSecretFile, fileErr)
|
||||
return "", fmt.Errorf("%w: %s: %s", ErrReadSecretFile, filepath, fileErr)
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: %s", ErrReadSecretFile, err)
|
||||
return "", fmt.Errorf("%w: %s: %s", ErrReadSecretFile, filepath, err)
|
||||
}
|
||||
|
||||
value = string(b)
|
||||
value = cleanSuffix(value)
|
||||
if compulsory && value == "" {
|
||||
return "", ErrSecretFileIsEmpty
|
||||
return "", fmt.Errorf("%s: %w", filepath, ErrSecretFileIsEmpty)
|
||||
}
|
||||
|
||||
return value, nil
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"net"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
type ServerSelection struct { //nolint:maligned
|
||||
@@ -16,14 +15,12 @@ type ServerSelection struct { //nolint:maligned
|
||||
// Cyberghost, PIA, Protonvpn, Surfshark, Windscribe, Vyprvpn, NordVPN
|
||||
Regions []string `json:"regions"`
|
||||
|
||||
// Cyberghost
|
||||
Groups []string `json:"groups"`
|
||||
|
||||
// Fastestvpn, HideMyAss, IPVanish, IVPN, Mullvad, PrivateVPN, Protonvpn, PureVPN, VPNUnlimited
|
||||
// Expressvpn, Fastestvpn, HideMyAss, IPVanish, IVPN, Mullvad, PrivateVPN, Protonvpn, PureVPN, VPNUnlimited
|
||||
Countries []string `json:"countries"`
|
||||
// HideMyAss, IPVanish, IVPN, Mullvad, PrivateVPN, Protonvpn, PureVPN, VPNUnlimited, Windscribe
|
||||
// Expressvpn, HideMyAss, IPVanish, IVPN, Mullvad, Perfectprivacy, PrivateVPN, Protonvpn,
|
||||
// PureVPN, VPNUnlimited, WeVPN, Windscribe
|
||||
Cities []string `json:"cities"`
|
||||
// Fastestvpn, HideMyAss, IPVanish, IVPN, PrivateVPN, Windscribe, Privado, Protonvpn, VPNUnlimited
|
||||
// Expressvpn, Fastestvpn, HideMyAss, IPVanish, IVPN, PrivateVPN, Windscribe, Privado, Protonvpn, VPNUnlimited, WeVPN
|
||||
Hostnames []string `json:"hostnames"`
|
||||
Names []string `json:"names"` // Protonvpn
|
||||
|
||||
@@ -40,6 +37,9 @@ type ServerSelection struct { //nolint:maligned
|
||||
// VPNUnlimited
|
||||
StreamOnly bool `json:"stream_only"`
|
||||
|
||||
// Surfshark
|
||||
MultiHopOnly bool `json:"multihop_only"`
|
||||
|
||||
OpenVPN OpenVPNSelection `json:"openvpn"`
|
||||
Wireguard WireguardSelection `json:"wireguard"`
|
||||
}
|
||||
@@ -49,10 +49,6 @@ func (selection ServerSelection) toLines() (lines []string) {
|
||||
lines = append(lines, lastIndent+"Target IP address: "+selection.TargetIP.String())
|
||||
}
|
||||
|
||||
if len(selection.Groups) > 0 {
|
||||
lines = append(lines, lastIndent+"Server groups: "+commaJoin(selection.Groups))
|
||||
}
|
||||
|
||||
if len(selection.Countries) > 0 {
|
||||
lines = append(lines, lastIndent+"Countries: "+commaJoin(selection.Countries))
|
||||
}
|
||||
@@ -103,14 +99,19 @@ func (selection ServerSelection) toLines() (lines []string) {
|
||||
}
|
||||
|
||||
type OpenVPNSelection struct {
|
||||
ConfFile string `json:"conf_file"` // Custom configuration file path
|
||||
TCP bool `json:"tcp"` // UDP if TCP is false
|
||||
CustomPort uint16 `json:"custom_port"` // HideMyAss, Mullvad, PIA, ProtonVPN, Windscribe
|
||||
CustomPort uint16 `json:"custom_port"` // HideMyAss, Mullvad, PIA, ProtonVPN, WeVPN, Windscribe
|
||||
EncPreset string `json:"encryption_preset"` // PIA - needed to get the port number
|
||||
}
|
||||
|
||||
func (settings *OpenVPNSelection) lines() (lines []string) {
|
||||
lines = append(lines, lastIndent+"OpenVPN selection:")
|
||||
|
||||
if settings.ConfFile != "" {
|
||||
lines = append(lines, indent+lastIndent+"Custom configuration file: "+settings.ConfFile)
|
||||
}
|
||||
|
||||
lines = append(lines, indent+lastIndent+"Protocol: "+protoToString(settings.TCP))
|
||||
|
||||
if settings.CustomPort != 0 {
|
||||
@@ -124,34 +125,52 @@ func (settings *OpenVPNSelection) lines() (lines []string) {
|
||||
return lines
|
||||
}
|
||||
|
||||
func (settings *OpenVPNSelection) readProtocolOnly(env params.Interface) (err error) {
|
||||
settings.TCP, err = readProtocol(env)
|
||||
func (settings *OpenVPNSelection) readProtocolOnly(r reader) (err error) {
|
||||
settings.TCP, err = readOpenVPNProtocol(r)
|
||||
return err
|
||||
}
|
||||
|
||||
func (settings *OpenVPNSelection) readProtocolAndPort(env params.Interface) (err error) {
|
||||
settings.TCP, err = readProtocol(env)
|
||||
func (settings *OpenVPNSelection) readProtocolAndPort(r reader) (err error) {
|
||||
settings.TCP, err = readOpenVPNProtocol(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.CustomPort, err = readPortOrZero(env, "PORT")
|
||||
settings.CustomPort, err = readOpenVPNCustomPort(r, openvpnPortValidation{allAllowed: true})
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable PORT: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type WireguardSelection struct {
|
||||
CustomPort uint16 `json:"custom_port"` // Mullvad
|
||||
// EndpointPort is a the server port to use for the VPN server.
|
||||
// It is optional for Wireguard VPN providers IVPN, Mullvad
|
||||
// and Windscribe, and compulsory for the others
|
||||
EndpointPort uint16 `json:"port,omitempty"`
|
||||
// PublicKey is the server public key.
|
||||
// It is only used with VPN providers generating Wireguard
|
||||
// configurations specific to each server and user.
|
||||
PublicKey string `json:"publickey,omitempty"`
|
||||
// EndpointIP is the server endpoint IP address.
|
||||
// It is only used with VPN providers generating Wireguard
|
||||
// configurations specific to each server and user.
|
||||
EndpointIP net.IP `json:"endpoint_ip,omitempty"`
|
||||
}
|
||||
|
||||
func (settings *WireguardSelection) lines() (lines []string) {
|
||||
lines = append(lines, lastIndent+"Wireguard selection:")
|
||||
|
||||
if settings.CustomPort != 0 {
|
||||
lines = append(lines, indent+lastIndent+"Custom port: "+fmt.Sprint(settings.CustomPort))
|
||||
if settings.PublicKey != "" {
|
||||
lines = append(lines, indent+lastIndent+"Public key: "+settings.PublicKey)
|
||||
}
|
||||
|
||||
if settings.EndpointIP != nil {
|
||||
endpoint := settings.EndpointIP.String() + ":" + fmt.Sprint(settings.EndpointPort)
|
||||
lines = append(lines, indent+lastIndent+"Server endpoint: "+endpoint)
|
||||
} else if settings.EndpointPort != 0 {
|
||||
lines = append(lines, indent+lastIndent+"Custom port: "+fmt.Sprint(settings.EndpointPort))
|
||||
}
|
||||
|
||||
return lines
|
||||
|
||||
@@ -40,7 +40,7 @@ func (settings *ControlServer) read(r reader) (err error) {
|
||||
settings.Port, warning, err = r.env.ListeningPort(
|
||||
"HTTP_CONTROL_SERVER_PORT", params.Default("8000"))
|
||||
if len(warning) > 0 {
|
||||
r.logger.Warn(warning)
|
||||
r.warner.Warn(warning)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable HTTP_CONTROL_SERVER_PORT: %w", err)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
@@ -22,6 +22,7 @@ type Settings struct {
|
||||
VersionInformation bool
|
||||
ControlServer ControlServer
|
||||
Health Health
|
||||
Log Log
|
||||
}
|
||||
|
||||
func (settings *Settings) String() string {
|
||||
@@ -33,6 +34,7 @@ func (settings *Settings) lines() (lines []string) {
|
||||
lines = append(lines, settings.VPN.lines()...)
|
||||
lines = append(lines, settings.DNS.lines()...)
|
||||
lines = append(lines, settings.Firewall.lines()...)
|
||||
lines = append(lines, settings.Log.lines()...)
|
||||
lines = append(lines, settings.System.lines()...)
|
||||
lines = append(lines, settings.HTTPProxy.lines()...)
|
||||
lines = append(lines, settings.ShadowSocks.lines()...)
|
||||
@@ -57,12 +59,14 @@ var (
|
||||
ErrUpdater = errors.New("cannot read Updater settings")
|
||||
ErrPublicIP = errors.New("cannot read Public IP getter settings")
|
||||
ErrHealth = errors.New("cannot read health settings")
|
||||
ErrLog = errors.New("cannot read log settings")
|
||||
)
|
||||
|
||||
// Read obtains all configuration options for the program and returns an error as soon
|
||||
// as an error is encountered reading them.
|
||||
func (settings *Settings) Read(env params.Interface, logger logging.Logger) (err error) {
|
||||
r := newReader(env, logger)
|
||||
func (settings *Settings) Read(env params.Interface, servers models.AllServers,
|
||||
warner Warner) (err error) {
|
||||
r := newReader(env, servers, warner)
|
||||
|
||||
settings.VersionInformation, err = r.env.OnOff("VERSION_INFORMATION", params.Default("on"))
|
||||
if err != nil {
|
||||
@@ -113,5 +117,9 @@ func (settings *Settings) Read(env params.Interface, logger logging.Logger) (err
|
||||
return fmt.Errorf("%w: %s", ErrHealth, err)
|
||||
}
|
||||
|
||||
if err := settings.Log.read(r.env); err != nil {
|
||||
return fmt.Errorf("%w: %s", ErrLog, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -43,13 +43,16 @@ func Test_Settings_lines(t *testing.T) {
|
||||
" |--Protocol: udp",
|
||||
"|--DNS:",
|
||||
"|--Firewall: disabled ⚠️",
|
||||
"|--Log:",
|
||||
" |--Level: DEBUG",
|
||||
"|--System:",
|
||||
" |--Process user ID: 0",
|
||||
" |--Process group ID: 0",
|
||||
" |--Timezone: NOT SET ⚠️ - it can cause time related issues",
|
||||
"|--Health:",
|
||||
" |--Server address: ",
|
||||
" |--OpenVPN:",
|
||||
" |--Address to ping: ",
|
||||
" |--VPN:",
|
||||
" |--Initial duration: 0s",
|
||||
"|--HTTP control server:",
|
||||
" |--Listening port: 0",
|
||||
|
||||
@@ -62,7 +62,7 @@ func (settings *ShadowSocks) read(r reader) (err error) {
|
||||
|
||||
warning, err := settings.getAddress(r.env)
|
||||
if warning != "" {
|
||||
r.logger.Warn(warning)
|
||||
r.warner.Warn(warning)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -2,27 +2,101 @@ package configuration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
func (settings *Provider) readSurfshark(r reader) (err error) {
|
||||
settings.Name = constants.Surfshark
|
||||
servers := r.servers.GetSurfshark()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.SurfsharkRegionChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.SurfsharkCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.SurfsharkHostnameChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.SurfsharkCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.SurfsharkHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||
regionChoices := constants.SurfsharkRegionChoices(servers)
|
||||
regionChoices = append(regionChoices, constants.SurfsharkRetroLocChoices(servers)...)
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", regionChoices)
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
// Retro compatibility
|
||||
// TODO remove in v4
|
||||
settings.ServerSelection = surfsharkRetroRegion(settings.ServerSelection)
|
||||
|
||||
settings.ServerSelection.MultiHopOnly, err = r.env.YesNo("MULTIHOP_ONLY", params.Default("no"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable MULTIHOP_ONLY: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r)
|
||||
}
|
||||
|
||||
func surfsharkRetroRegion(selection ServerSelection) (
|
||||
updatedSelection ServerSelection) {
|
||||
locationData := constants.SurfsharkLocationData()
|
||||
|
||||
retroToLocation := make(map[string]models.SurfsharkLocationData, len(locationData))
|
||||
for _, data := range locationData {
|
||||
if data.RetroLoc == "" {
|
||||
continue
|
||||
}
|
||||
retroToLocation[strings.ToLower(data.RetroLoc)] = data
|
||||
}
|
||||
|
||||
for i, region := range selection.Regions {
|
||||
location, ok := retroToLocation[region]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
selection.Regions[i] = strings.ToLower(location.Region)
|
||||
selection.Countries = append(selection.Countries, strings.ToLower(location.Country))
|
||||
selection.Cities = append(selection.Cities, strings.ToLower(location.City)) // even empty string
|
||||
selection.Hostnames = append(selection.Hostnames, location.Hostname)
|
||||
}
|
||||
|
||||
selection.Regions = dedupSlice(selection.Regions)
|
||||
selection.Countries = dedupSlice(selection.Countries)
|
||||
selection.Cities = dedupSlice(selection.Cities)
|
||||
selection.Hostnames = dedupSlice(selection.Hostnames)
|
||||
|
||||
return selection
|
||||
}
|
||||
|
||||
func dedupSlice(slice []string) (deduped []string) {
|
||||
if slice == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
deduped = make([]string, 0, len(slice))
|
||||
seen := make(map[string]struct{}, len(slice))
|
||||
for _, s := range slice {
|
||||
if _, ok := seen[s]; !ok {
|
||||
seen[s] = struct{}{}
|
||||
deduped = append(deduped, s)
|
||||
}
|
||||
}
|
||||
|
||||
return deduped
|
||||
}
|
||||
|
||||
305
internal/configuration/surfshark_test.go
Normal file
305
internal/configuration/surfshark_test.go
Normal file
@@ -0,0 +1,305 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/params/mock_params"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_Provider_readSurfshark(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var errDummy = errors.New("dummy test error")
|
||||
|
||||
type stringCall struct {
|
||||
call bool
|
||||
value string
|
||||
err error
|
||||
}
|
||||
|
||||
type boolCall struct {
|
||||
call bool
|
||||
value bool
|
||||
err error
|
||||
}
|
||||
|
||||
type sliceStringCall struct {
|
||||
call bool
|
||||
values []string
|
||||
err error
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
targetIP stringCall
|
||||
countries sliceStringCall
|
||||
cities sliceStringCall
|
||||
hostnames sliceStringCall
|
||||
regions sliceStringCall
|
||||
multiHop boolCall
|
||||
protocol stringCall
|
||||
settings Provider
|
||||
err error
|
||||
}{
|
||||
"target IP error": {
|
||||
targetIP: stringCall{call: true, value: "something", err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable OPENVPN_TARGET_IP: dummy test error"),
|
||||
},
|
||||
"countries error": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable COUNTRY: dummy test error"),
|
||||
},
|
||||
"cities error": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable CITY: dummy test error"),
|
||||
},
|
||||
"hostnames error": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable SERVER_HOSTNAME: dummy test error"),
|
||||
},
|
||||
"regions error": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
regions: sliceStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable REGION: dummy test error"),
|
||||
},
|
||||
"multi hop error": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
regions: sliceStringCall{call: true},
|
||||
multiHop: boolCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable MULTIHOP_ONLY: dummy test error"),
|
||||
},
|
||||
"openvpn protocol error": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
regions: sliceStringCall{call: true},
|
||||
multiHop: boolCall{call: true},
|
||||
protocol: stringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable OPENVPN_PROTOCOL: dummy test error"),
|
||||
},
|
||||
"default settings": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
regions: sliceStringCall{call: true},
|
||||
multiHop: boolCall{call: true},
|
||||
protocol: stringCall{call: true},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
},
|
||||
"set settings": {
|
||||
targetIP: stringCall{call: true, value: "1.2.3.4"},
|
||||
countries: sliceStringCall{call: true, values: []string{"A", "B"}},
|
||||
cities: sliceStringCall{call: true, values: []string{"C", "D"}},
|
||||
regions: sliceStringCall{call: true, values: []string{
|
||||
"E", "F", "netherlands amsterdam",
|
||||
}}, // Netherlands Amsterdam is for retro compatibility test
|
||||
multiHop: boolCall{call: true},
|
||||
hostnames: sliceStringCall{call: true, values: []string{"E", "F"}},
|
||||
protocol: stringCall{call: true, value: constants.TCP},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
ServerSelection: ServerSelection{
|
||||
OpenVPN: OpenVPNSelection{
|
||||
TCP: true,
|
||||
},
|
||||
TargetIP: net.IPv4(1, 2, 3, 4),
|
||||
Regions: []string{"E", "F", "europe"},
|
||||
Countries: []string{"A", "B", "netherlands"},
|
||||
Cities: []string{"C", "D", "amsterdam"},
|
||||
Hostnames: []string{"E", "F", "nl-ams.prod.surfshark.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"Netherlands Amsterdam": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
regions: sliceStringCall{call: true, values: []string{"netherlands amsterdam"}},
|
||||
multiHop: boolCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
protocol: stringCall{call: true},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
ServerSelection: ServerSelection{
|
||||
Regions: []string{"europe"},
|
||||
Countries: []string{"netherlands"},
|
||||
Cities: []string{"amsterdam"},
|
||||
Hostnames: []string{"nl-ams.prod.surfshark.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
env := mock_params.NewMockInterface(ctrl)
|
||||
|
||||
servers := []models.SurfsharkServer{{Hostname: "a"}}
|
||||
allServers := models.AllServers{
|
||||
Surfshark: models.SurfsharkServers{
|
||||
Servers: servers,
|
||||
},
|
||||
}
|
||||
|
||||
if testCase.targetIP.call {
|
||||
env.EXPECT().Get("OPENVPN_TARGET_IP").
|
||||
Return(testCase.targetIP.value, testCase.targetIP.err)
|
||||
}
|
||||
if testCase.countries.call {
|
||||
env.EXPECT().CSVInside("COUNTRY", constants.SurfsharkCountryChoices(servers)).
|
||||
Return(testCase.countries.values, testCase.countries.err)
|
||||
}
|
||||
if testCase.cities.call {
|
||||
env.EXPECT().CSVInside("CITY", constants.SurfsharkCityChoices(servers)).
|
||||
Return(testCase.cities.values, testCase.cities.err)
|
||||
}
|
||||
if testCase.hostnames.call {
|
||||
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.SurfsharkHostnameChoices(servers)).
|
||||
Return(testCase.hostnames.values, testCase.hostnames.err)
|
||||
}
|
||||
if testCase.regions.call {
|
||||
regionChoices := constants.SurfsharkRegionChoices(servers)
|
||||
regionChoices = append(regionChoices, constants.SurfsharkRetroLocChoices(servers)...)
|
||||
env.EXPECT().CSVInside("REGION", regionChoices).
|
||||
Return(testCase.regions.values, testCase.regions.err)
|
||||
}
|
||||
if testCase.multiHop.call {
|
||||
env.EXPECT().YesNo("MULTIHOP_ONLY", gomock.Any()).
|
||||
Return(testCase.multiHop.value, testCase.multiHop.err)
|
||||
}
|
||||
if testCase.protocol.call {
|
||||
env.EXPECT().Inside("OPENVPN_PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
|
||||
Return(testCase.protocol.value, testCase.protocol.err)
|
||||
}
|
||||
|
||||
r := reader{
|
||||
servers: allServers,
|
||||
env: env,
|
||||
}
|
||||
|
||||
var settings Provider
|
||||
err := settings.readSurfshark(r)
|
||||
|
||||
if testCase.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, testCase.err.Error(), err.Error())
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.Equal(t, testCase.settings, settings)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_surfsharkRetroRegion(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
original ServerSelection
|
||||
modified ServerSelection
|
||||
}{
|
||||
"empty": {},
|
||||
"1 retro region": {
|
||||
original: ServerSelection{
|
||||
Regions: []string{"australia adelaide"},
|
||||
},
|
||||
modified: ServerSelection{
|
||||
Regions: []string{"asia pacific"},
|
||||
Countries: []string{"australia"},
|
||||
Cities: []string{"adelaide"},
|
||||
Hostnames: []string{"au-adl.prod.surfshark.com"},
|
||||
},
|
||||
},
|
||||
"2 overlapping retro regions": {
|
||||
original: ServerSelection{
|
||||
Regions: []string{"australia adelaide", "australia melbourne"},
|
||||
},
|
||||
modified: ServerSelection{
|
||||
Regions: []string{"asia pacific"},
|
||||
Countries: []string{"australia"},
|
||||
Cities: []string{"adelaide", "melbourne"},
|
||||
Hostnames: []string{"au-adl.prod.surfshark.com", "au-mel.prod.surfshark.com"},
|
||||
},
|
||||
},
|
||||
"2 distinct retro regions": {
|
||||
original: ServerSelection{
|
||||
Regions: []string{"australia adelaide", "netherlands amsterdam"},
|
||||
},
|
||||
modified: ServerSelection{
|
||||
Regions: []string{"asia pacific", "europe"},
|
||||
Countries: []string{"australia", "netherlands"},
|
||||
Cities: []string{"adelaide", "amsterdam"},
|
||||
Hostnames: []string{"au-adl.prod.surfshark.com", "nl-ams.prod.surfshark.com"},
|
||||
},
|
||||
},
|
||||
"retro region with existing region": {
|
||||
// note TestRegion will be ignored in the filters downstream
|
||||
original: ServerSelection{
|
||||
Regions: []string{"TestRegion", "australia adelaide"},
|
||||
},
|
||||
modified: ServerSelection{
|
||||
Regions: []string{"TestRegion", "asia pacific"},
|
||||
Countries: []string{"australia"},
|
||||
Cities: []string{"adelaide"},
|
||||
Hostnames: []string{"au-adl.prod.surfshark.com"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
selection := surfsharkRetroRegion(testCase.original)
|
||||
|
||||
assert.Equal(t, testCase.modified, selection)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -8,26 +8,28 @@ import (
|
||||
|
||||
func (settings *Provider) readTorguard(r reader) (err error) {
|
||||
settings.Name = constants.Torguard
|
||||
servers := r.servers.GetTorguard()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.TorguardCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.TorguardCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.TorguardCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.TorguardCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.TorguardHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.TorguardHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r.env)
|
||||
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r)
|
||||
}
|
||||
|
||||
@@ -9,25 +9,28 @@ import (
|
||||
)
|
||||
|
||||
type Updater struct {
|
||||
Period time.Duration `json:"period"`
|
||||
DNSAddress string `json:"dns_address"`
|
||||
Cyberghost bool `json:"cyberghost"`
|
||||
Fastestvpn bool `json:"fastestvpn"`
|
||||
HideMyAss bool `json:"hidemyass"`
|
||||
Ipvanish bool `json:"ipvanish"`
|
||||
Ivpn bool `json:"ivpn"`
|
||||
Mullvad bool `json:"mullvad"`
|
||||
Nordvpn bool `json:"nordvpn"`
|
||||
PIA bool `json:"pia"`
|
||||
Privado bool `json:"privado"`
|
||||
Privatevpn bool `json:"privatevpn"`
|
||||
Protonvpn bool `json:"protonvpn"`
|
||||
Purevpn bool `json:"purevpn"`
|
||||
Surfshark bool `json:"surfshark"`
|
||||
Torguard bool `json:"torguard"`
|
||||
VPNUnlimited bool `json:"vpnunlimited"`
|
||||
Vyprvpn bool `json:"vyprvpn"`
|
||||
Windscribe bool `json:"windscribe"`
|
||||
Period time.Duration `json:"period"`
|
||||
DNSAddress string `json:"dns_address"`
|
||||
Cyberghost bool `json:"cyberghost"`
|
||||
Expressvpn bool `json:"expressvpn"`
|
||||
Fastestvpn bool `json:"fastestvpn"`
|
||||
HideMyAss bool `json:"hidemyass"`
|
||||
Ipvanish bool `json:"ipvanish"`
|
||||
Ivpn bool `json:"ivpn"`
|
||||
Mullvad bool `json:"mullvad"`
|
||||
Nordvpn bool `json:"nordvpn"`
|
||||
Perfectprivacy bool `json:"perfectprivacy"`
|
||||
PIA bool `json:"pia"`
|
||||
Privado bool `json:"privado"`
|
||||
Privatevpn bool `json:"privatevpn"`
|
||||
Protonvpn bool `json:"protonvpn"`
|
||||
Purevpn bool `json:"purevpn"`
|
||||
Surfshark bool `json:"surfshark"`
|
||||
Torguard bool `json:"torguard"`
|
||||
VPNUnlimited bool `json:"vpnunlimited"`
|
||||
Vyprvpn bool `json:"vyprvpn"`
|
||||
Wevpn bool `json:"wevpn"`
|
||||
Windscribe bool `json:"windscribe"`
|
||||
// The two below should be used in CLI mode only
|
||||
CLI bool `json:"-"`
|
||||
}
|
||||
@@ -55,6 +58,7 @@ func (settings *Updater) EnableAll() {
|
||||
settings.Ivpn = true
|
||||
settings.Mullvad = true
|
||||
settings.Nordvpn = true
|
||||
settings.Perfectprivacy = true
|
||||
settings.Privado = true
|
||||
settings.PIA = true
|
||||
settings.Privado = true
|
||||
@@ -65,6 +69,7 @@ func (settings *Updater) EnableAll() {
|
||||
settings.Torguard = true
|
||||
settings.VPNUnlimited = true
|
||||
settings.Vyprvpn = true
|
||||
settings.Wevpn = true
|
||||
settings.Windscribe = true
|
||||
}
|
||||
|
||||
|
||||
@@ -58,10 +58,8 @@ func (settings *VPN) read(r reader) (err error) {
|
||||
}
|
||||
settings.Type = vpnType
|
||||
|
||||
if !settings.isOpenVPNCustomConfig(r.env) {
|
||||
if err := settings.Provider.read(r, vpnType); err != nil {
|
||||
return fmt.Errorf("%w: %s", errReadProviderSettings, err)
|
||||
}
|
||||
if err := settings.Provider.read(r, vpnType); err != nil {
|
||||
return fmt.Errorf("%w: %s", errReadProviderSettings, err)
|
||||
}
|
||||
|
||||
switch settings.Type {
|
||||
@@ -79,11 +77,3 @@ func (settings *VPN) read(r reader) (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (settings VPN) isOpenVPNCustomConfig(env params.Interface) (ok bool) {
|
||||
if settings.Type != constants.OpenVPN {
|
||||
return false
|
||||
}
|
||||
s, err := env.Get("OPENVPN_CUSTOM_CONFIG")
|
||||
return err == nil && s != ""
|
||||
}
|
||||
|
||||
@@ -9,23 +9,25 @@ import (
|
||||
|
||||
func (settings *Provider) readVPNUnlimited(r reader) (err error) {
|
||||
settings.Name = constants.VPNUnlimited
|
||||
servers := r.servers.GetVPNUnlimited()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.VPNUnlimitedCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.VPNUnlimitedCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.VPNUnlimitedCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.VPNUnlimitedCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.VPNUnlimitedHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.VPNUnlimitedHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
@@ -40,18 +42,18 @@ func (settings *Provider) readVPNUnlimited(r reader) (err error) {
|
||||
return fmt.Errorf("environment variable STREAM_ONLY: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r)
|
||||
}
|
||||
|
||||
func (settings *OpenVPN) readVPNUnlimited(r reader) (err error) {
|
||||
settings.ClientKey, err = readClientKey(r)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("%w: %s", errClientKey, err)
|
||||
}
|
||||
|
||||
settings.ClientCrt, err = readClientCertificate(r)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("%w: %s", errClientCert, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -8,13 +8,14 @@ import (
|
||||
|
||||
func (settings *Provider) readVyprvpn(r reader) (err error) {
|
||||
settings.Name = constants.Vyprvpn
|
||||
servers := r.servers.GetVyprvpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.VyprvpnRegionChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.VyprvpnRegionChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
46
internal/configuration/warner_mock_test.go
Normal file
46
internal/configuration/warner_mock_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/qdm12/gluetun/internal/configuration (interfaces: Warner)
|
||||
|
||||
// Package configuration is a generated GoMock package.
|
||||
package configuration
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockWarner is a mock of Warner interface.
|
||||
type MockWarner struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockWarnerMockRecorder
|
||||
}
|
||||
|
||||
// MockWarnerMockRecorder is the mock recorder for MockWarner.
|
||||
type MockWarnerMockRecorder struct {
|
||||
mock *MockWarner
|
||||
}
|
||||
|
||||
// NewMockWarner creates a new mock instance.
|
||||
func NewMockWarner(ctrl *gomock.Controller) *MockWarner {
|
||||
mock := &MockWarner{ctrl: ctrl}
|
||||
mock.recorder = &MockWarnerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockWarner) EXPECT() *MockWarnerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Warn mocks base method.
|
||||
func (m *MockWarner) Warn(arg0 string) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Warn", arg0)
|
||||
}
|
||||
|
||||
// Warn indicates an expected call of Warn.
|
||||
func (mr *MockWarnerMockRecorder) Warn(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockWarner)(nil).Warn), arg0)
|
||||
}
|
||||
57
internal/configuration/wevpn.go
Normal file
57
internal/configuration/wevpn.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
)
|
||||
|
||||
func (settings *Provider) readWevpn(r reader) (err error) {
|
||||
settings.Name = constants.Wevpn
|
||||
servers := r.servers.GetWevpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.WevpnCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.WevpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readWevpn(r)
|
||||
}
|
||||
|
||||
func (settings *OpenVPNSelection) readWevpn(r reader) (err error) {
|
||||
settings.TCP, err = readOpenVPNProtocol(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
validation := openvpnPortValidation{
|
||||
tcp: settings.TCP,
|
||||
allowedTCP: []uint16{53, 1195, 1199, 2018},
|
||||
allowedUDP: []uint16{80, 1194, 1198},
|
||||
}
|
||||
settings.CustomPort, err = readOpenVPNCustomPort(r, validation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (settings *OpenVPN) readWevpn(r reader) (err error) {
|
||||
settings.ClientKey, err = readClientKey(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -9,28 +9,30 @@ import (
|
||||
|
||||
func (settings *Provider) readWindscribe(r reader) (err error) {
|
||||
settings.Name = constants.Windscribe
|
||||
servers := r.servers.GetWindscribe()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.WindscribeRegionChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.WindscribeRegionChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.WindscribeCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.WindscribeCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.WindscribeHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.WindscribeHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
err = settings.ServerSelection.OpenVPN.readWindscribe(r.env)
|
||||
err = settings.ServerSelection.OpenVPN.readWindscribe(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -38,15 +40,17 @@ func (settings *Provider) readWindscribe(r reader) (err error) {
|
||||
return settings.ServerSelection.Wireguard.readWindscribe(r.env)
|
||||
}
|
||||
|
||||
func (settings *OpenVPNSelection) readWindscribe(env params.Interface) (err error) {
|
||||
settings.TCP, err = readProtocol(env)
|
||||
func (settings *OpenVPNSelection) readWindscribe(r reader) (err error) {
|
||||
settings.TCP, err = readOpenVPNProtocol(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.CustomPort, err = readOpenVPNCustomPort(env, settings.TCP,
|
||||
[]uint16{21, 22, 80, 123, 143, 443, 587, 1194, 3306, 8080, 54783},
|
||||
[]uint16{53, 80, 123, 443, 1194, 54783})
|
||||
settings.CustomPort, err = readOpenVPNCustomPort(r, openvpnPortValidation{
|
||||
tcp: settings.TCP,
|
||||
allowedTCP: []uint16{21, 22, 80, 123, 143, 443, 587, 1194, 3306, 8080, 54783},
|
||||
allowedUDP: []uint16{53, 80, 123, 443, 1194, 54783},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -55,7 +59,7 @@ func (settings *OpenVPNSelection) readWindscribe(env params.Interface) (err erro
|
||||
}
|
||||
|
||||
func (settings *WireguardSelection) readWindscribe(env params.Interface) (err error) {
|
||||
settings.CustomPort, err = readWireguardCustomPort(env,
|
||||
settings.EndpointPort, err = readWireguardCustomPort(env,
|
||||
[]uint16{53, 80, 123, 443, 1194, 65142})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
|
||||
// Wireguard contains settings to configure the Wireguard client.
|
||||
type Wireguard struct {
|
||||
PrivateKey string `json:"privatekey"`
|
||||
PreSharedKey string `json:"presharedkey"`
|
||||
Address *net.IPNet `json:"address"`
|
||||
Interface string `json:"interface"`
|
||||
PrivateKey string `json:"privatekey"`
|
||||
PreSharedKey string `json:"presharedkey"`
|
||||
Addresses []*net.IPNet `json:"addresses"`
|
||||
Interface string `json:"interface"`
|
||||
}
|
||||
|
||||
func (settings *Wireguard) String() string {
|
||||
@@ -33,8 +33,11 @@ func (settings *Wireguard) lines() (lines []string) {
|
||||
lines = append(lines, indent+lastIndent+"Pre-shared key is set")
|
||||
}
|
||||
|
||||
if settings.Address != nil {
|
||||
lines = append(lines, indent+lastIndent+"Address: "+settings.Address.String())
|
||||
if len(settings.Addresses) > 0 {
|
||||
lines = append(lines, indent+lastIndent+"Addresses: ")
|
||||
for _, address := range settings.Addresses {
|
||||
lines = append(lines, indent+indent+lastIndent+address.String())
|
||||
}
|
||||
}
|
||||
|
||||
return lines
|
||||
@@ -53,16 +56,10 @@ func (settings *Wireguard) read(r reader) (err error) {
|
||||
return fmt.Errorf("environment variable WIREGUARD_PRESHARED_KEY: %w", err)
|
||||
}
|
||||
|
||||
addressString, err := r.env.Get("WIREGUARD_ADDRESS", params.Compulsory())
|
||||
err = settings.readAddresses(r.env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable WIREGUARD_ADDRESS: %w", err)
|
||||
return err
|
||||
}
|
||||
ip, ipNet, err := net.ParseCIDR(addressString)
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable WIREGUARD_ADDRESS: %w", err)
|
||||
}
|
||||
ipNet.IP = ip
|
||||
settings.Address = ipNet
|
||||
|
||||
settings.Interface, err = r.env.Get("WIREGUARD_INTERFACE", params.Default("wg0"))
|
||||
if err != nil {
|
||||
@@ -71,3 +68,21 @@ func (settings *Wireguard) read(r reader) (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (settings *Wireguard) readAddresses(env params.Interface) (err error) {
|
||||
addressStrings, err := env.CSV("WIREGUARD_ADDRESS", params.Compulsory())
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable WIREGUARD_ADDRESS: %w", err)
|
||||
}
|
||||
|
||||
for _, addressString := range addressStrings {
|
||||
ip, ipNet, err := net.ParseCIDR(addressString)
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable WIREGUARD_ADDRESS: address %s: %w", addressString, err)
|
||||
}
|
||||
ipNet.IP = ip
|
||||
settings.Addresses = append(settings.Addresses, ipNet)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
@@ -11,46 +9,18 @@ const (
|
||||
CyberghostCertificate = "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"
|
||||
)
|
||||
|
||||
func CyberghostRegionChoices() (choices []string) {
|
||||
servers := CyberghostServers()
|
||||
func CyberghostCountryChoices(servers []models.CyberghostServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
choices[i] = servers[i].Country
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func CyberghostGroupChoices() (choices []string) {
|
||||
servers := CyberghostServers()
|
||||
uniqueChoices := map[string]struct{}{}
|
||||
for _, server := range servers {
|
||||
uniqueChoices[server.Group] = struct{}{}
|
||||
}
|
||||
|
||||
choices = make([]string, 0, len(uniqueChoices))
|
||||
for choice := range uniqueChoices {
|
||||
choices = append(choices, choice)
|
||||
}
|
||||
|
||||
sortable := sort.StringSlice(choices)
|
||||
sortable.Sort()
|
||||
|
||||
return sortable
|
||||
}
|
||||
|
||||
func CyberghostHostnameChoices() (choices []string) {
|
||||
servers := CyberghostServers()
|
||||
func CyberghostHostnameChoices(servers []models.CyberghostServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// CyberghostServers returns a slice with the server information for each
|
||||
// of the Cyberghost server.
|
||||
func CyberghostServers() (servers []models.CyberghostServer) {
|
||||
servers = make([]models.CyberghostServer, len(allServers.Cyberghost.Servers))
|
||||
copy(servers, allServers.Cyberghost.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_CyberghostGroupChoices(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
expected := []string{"Premium TCP Asia", "Premium TCP Europe",
|
||||
"Premium TCP USA", "Premium UDP Asia", "Premium UDP Europe",
|
||||
"Premium UDP USA"}
|
||||
choices := CyberghostGroupChoices()
|
||||
|
||||
assert.Equal(t, expected, choices)
|
||||
}
|
||||
37
internal/constants/expressvpn.go
Normal file
37
internal/constants/expressvpn.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
//nolint:lll
|
||||
const (
|
||||
ExpressvpnCert = "MIIDTjCCAregAwIBAgIDKzZvMA0GCSqGSIb3DQEBCwUAMIGFMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFTATBgNVBAcTDFNhbkZyYW5jaXNjbzEVMBMGA1UEChMMRm9ydC1GdW5zdG9uMRgwFgYDVQQDEw9Gb3J0LUZ1bnN0b24gQ0ExITAfBgkqhkiG9w0BCQEWEm1lQG15aG9zdC5teWRvbWFpbjAgFw0xNjExMDMwMzA2MThaGA8yMDY2MTEwMzAzMDYxOFowgYoxCzAJBgNVBAYTAlZHMQwwCgYDVQQIDANCVkkxEzARBgNVBAoMCkV4cHJlc3NWUE4xEzARBgNVBAsMCkV4cHJlc3NWUE4xHDAaBgNVBAMME2V4cHJlc3N2cG5fY3VzdG9tZXIxJTAjBgkqhkiG9w0BCQEWFnN1cHBvcnRAZXhwcmVzc3Zwbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrOYt/KOi2uMDGev3pXg8j1SO4J/4EVWDF7vJcKr2jrZlqD/zuAFx2W1YWvwumPO6PKH4PU9621aNdiumaUkv/RplCfznnnxqobhJuTE2oA+rS1bOq+9OhHwF9jgNXNVk+XX4d0toST5uGE6Z3OdmPBur8o5AlCf78PDSAwpFOw5HrgLqOEU4hTweC1/czX2VsvsHv22HRI6JMZgP8gGQii/p9iukqfaJvGdPciL5p1QRBUQIi8P8pNvEp1pVIpxYj7/LOUqb2DxFvgmp2v1IQ0Yu88SWsFk84+xAYHzfkLyS31Sqj5uLRBnJqx3fIlOihQ50GI72fwPMwo+OippvVAgMBAAGjPzA9MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgSwMB0GA1UdDgQWBBSkBM1TCX9kBgFsv2RmOzudMXa9njANBgkqhkiG9w0BAQsFAAOBgQA+2e4b+33zFmA+1ZQ46kWkfiB+fEeDyMwMLeYYyDS2d8mZhNZKdOw7dy4Ifz9Vqzp4aKuQ6j61c6k1UaQQL0tskqWVzslSFvs9NZyUAJLLdGUc5TT2MiLwiXQwd4UvH6bGeePdhvB4+ZbW7VMD7TE8hZhjhAL4F6yAP1EQvg3LDA=="
|
||||
ExpressvpnRSAKey = "MIIEpAIBAAKCAQEAqzmLfyjotrjAxnr96V4PI9UjuCf+BFVgxe7yXCq9o62Zag/87gBcdltWFr8Lpjzujyh+D1PettWjXYrpmlJL/0aZQn85558aqG4SbkxNqAPq0tWzqvvToR8BfY4DVzVZPl1+HdLaEk+bhhOmdznZjwbq/KOQJQn+/Dw0gMKRTsOR64C6jhFOIU8Hgtf3M19lbL7B79th0SOiTGYD/IBkIov6fYrpKn2ibxnT3Ii+adUEQVECIvD/KTbxKdaVSKcWI+/yzlKm9g8Rb4Jqdr9SENGLvPElrBZPOPsQGB835C8kt9Uqo+bi0QZyasd3yJTooUOdBiO9n8DzMKPjoqab1QIDAQABAoIBAHgsekC0SKi+AOcNOZqJ3pxqophE0V7fQX2KWGXhxZnUZMFxGTc936deMYzjZ1y0lUa6x8cgOUcfqHol3hDmw9oWBckLHGv5Wi9umdb6DOLoZO62+FQATSdfaJ9jheq2Ub2YxsRN0apaXzB6KDKz0oM0+sZ4Udn9Kw6DfuIELRIWwEx4w0v3gKW7YLC4Jkc4AwLkPK03xEA/qImfkCmaMPLhrgVQt+IFfP8bXzL7CCC04rNU/IS8pyjex+iUolnQZlbXntF7Bm4V2mz0827ZVqrgAb/hEQRlsTW3rRkVh+rrdoUE7BCZRTFmRCbLoShjN6XuSf4sAus8ch4UEN12gN0CgYEA4o/tSvij1iPaXLmt4KOEuxqmSGB8MLKhFde8lBbNdrDgxiIH9bH7khKx15XRTX0qLDbs8b2/UJygZG0Aa1kIBqZTXTgeMAuxPRTesALJPdqQ/ROnbJcdFkI7gllrAG8VB0fH4wTRsRd0vWEB6YlCdE107u6LEsLAHxOj9Q5819cCgYEAwXjx9RkQ2qITBx5Ewib8YsltA0n3cmRomPicLlsnKV5DfvyCLpFIsZ1h3f9dUpfxRLwzp8wcoLiq9cCoOGdu1udw/yBTqmhaXWhUK/g77f9Ze2ZB1OEhuyKLYJ1vW/h/Z/a1aPCMxZqsDTPCePsuO8Cez5gqs8LjM3W7EyzRxDMCgYEAvhHrDFt975fSiLoJgo0MPIAGAnBXn+8sLwv3m/FpW+rWF8LTFK/Fku12H5wDpNOdvswxijkauIE+GiJMGMLvdcyx4WHECaC1h73reJRNykOEIZ0Md5BrCZJ1JEzp9Mo8RQhWTEFtvfkkqgApP4g0pSeaMx0StaGG1kt+4IbP+68CgYBrZdQKlquAck/Vt7u7eyDHRcE5/ilaWtqlb/xizz7h++3D5C/v4b5UumTFcyg+3RGVclPKZcfOgDSGzzeSd/hTW46iUTOgeOUQzQVMkzPRXdoyYgVRQtgSpY5xR3O1vjAbahwx8LZ0SvQPMBhYSDbV/Isr+fBacWjl/AipEEwxeQKBgQDdrAEnVlOFoCLw4sUjsPoxkLjhTAgI7CYk5NNxX67Rnj0tp+Y49+sGUhl5sCGfMKkLShiON5P2oxZa+B0aPtQjsdnsFPa1uaZkK4c++SS6AetzYRpVDLmLp7/1CulE0z3O0sBekpwiuaqLJ9ZccC81g4+2j8j6c50rIAct3hxIxw=="
|
||||
ExpressvpnTLSAuthOpenvpnStaticKeyV1 = "48d9999bd71095b10649c7cb471c1051b1afdece597cea06909b99303a18c67401597b12c04a787e98cdb619ee960d90a0165529dc650f3a5c6fbe77c91c137dcf55d863fcbe314df5f0b45dbe974d9bde33ef5b4803c3985531c6c23ca6906d6cd028efc8585d1b9e71003566bd7891b9cc9212bcba510109922eed87f5c8e66d8e59cbd82575261f02777372b2cd4ca5214c4a6513ff26dd568f574fd40d6cd450fc788160ff68434ce2bf6afb00e710a3198538f14c4d45d84ab42637872e778a6b35a124e700920879f1d003ba93dccdb953cdf32bea03f365760b0ed8002098d4ce20d045b45a83a8432cc737677aed27125592a7148d25c87fdbe0a3f6"
|
||||
ExpressvpnCA = "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"
|
||||
)
|
||||
|
||||
func ExpressvpnCountriesChoices(servers []models.ExpressvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func ExpressvpnCityChoices(servers []models.ExpressvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func ExpressvpnHostnameChoices(servers []models.ExpressvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
@@ -10,27 +10,18 @@ const (
|
||||
FastestvpnOpenvpnStaticKeyV1 = "697fe793b32cb5091d30f2326d5d124a9412e93d0a44ef7361395d76528fcbfc82c3859dccea70a93cfa8fae409709bff75f844cf5ff0c237f426d0c20969233db0e706edb6bdf195ec3dc11b3f76bc807a77e74662d9a800c8cd1144ebb67b7f0d3f1281d1baf522bfe03b7c3f963b1364fc0769400e413b61ca7b43ab19fac9e0f77e41efd4bda7fd77b1de2d7d7855cbbe3e620cecceac72c21a825b243e651f44d90e290e09c3ad650de8fca99c858bc7caad584bc69b11e5c9fd9381c69c505ec487a65912c672d83ed0113b5a74ddfbd3ab33b3683cec593557520a72c4d6cce46111f56f3396cc3ce7183edce553c68ea0796cf6c4375fad00aaa2a42"
|
||||
)
|
||||
|
||||
func FastestvpnCountriesChoices() (choices []string) {
|
||||
servers := FastestvpnServers()
|
||||
func FastestvpnCountriesChoices(servers []models.FastestvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
}
|
||||
return choices
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func FastestvpnHostnameChoices() (choices []string) {
|
||||
servers := FastestvpnServers()
|
||||
func FastestvpnHostnameChoices(servers []models.FastestvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return choices
|
||||
}
|
||||
|
||||
// FastestvpnServers returns the list of all VPN servers for FastestVPN.
|
||||
func FastestvpnServers() (servers []models.FastestvpnServer) {
|
||||
servers = make([]models.FastestvpnServer, len(allServers.Fastestvpn.Servers))
|
||||
copy(servers, allServers.Fastestvpn.Servers)
|
||||
return servers
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ const (
|
||||
HideMyAssRSAPrivateKey = "MIIEpAIBAAKCAQEA5XY3ERJYWs/YIeBoybivNlu+M32rJs+CAZsh7BnnetTxytI4ngsMRoqXETuis8udp2hsqEHsglLR9tlk9C8yCuKhxbkpdrXFWdISmUq5sa7/wqg/zJF1AZm5Jy0oHNyTHfG6XW61I/h9IN5dmcR9YLir8DVDBNllbtt0z+DnvOhYJOqC30ENahWkTmNKl1cT7EBrR5slddiBJleAb08z77pwsD310e6jWTBySsBcPy+xu/Jj2QgVil/3mstZZDI+noFzs3SkTFBkha/lNTP7NODBQ6m39iaJxz6ZR1xE3v7XU0H5WnpZIcQ2+kmu5Krk2y1GYMKL+9oaotXFPz9v+QIDAQABAoIBAQCcMcssOMOiFWc3MC3EWo4SP4MKQ9n0Uj5Z34LI151FdJyehlj54+VYQ1Cv71tCbjED2sZUBoP69mtsT/EzcsjqtfiOwgrifrs2+BOm+0HKHKiGlcbP9peiHkT10PxEITWXpYtJvGlbcfOjIxqt6B28cBjCK09ShrVQL9ylAKBearRRUacszppntMNTMtN/uG48ZR9Wm+xAczImdG6CrG5sLI/++JwM5PDChLvn5JgMGyOfQZdjNe1oSOVLmqFeG5uu/FS4oMon9+HtfjHJr4ZgA1yQ2wQh3GvEjlP8zwHxEpRJYbxpj6ZbjHZJ2HLX/Gcd9/cXiN8+fQ2zPIYQyG9dAoGBAPUUmt2nJNvl7gj0GbZZ3XR9o+hvj7bJ74W2NhMrw6kjrrzHTAUQd1sBQS8szAQCLqf2ou1aw9AMMBdsLAHydXxvbH7IBAla7rKr23iethtSfjhTNSgQLJHVZlNHfp3hzNtCQZ7j0qVjrteNotrdVF7kKPHDXAK00ICy6SPNjvrXAoGBAO+vdnO15jLeZbbi3lQNS4r8oCadyqyX7ouKE6MtKNhiPsNPGqHKiGcKs/+QylVgYvSmm7TgpsCAiEYeLSPT+Yq3y7HtwVpULlpfAhEJXmvn/6hGpOizx1WNGWhw7nHPWPDzf+jqCGzHdhK0aEZR3MZZQ+U+uKfGiJ8vrvgB7eGvAoGAWxxp5nU48rcsIw/8bxpBhgkfYk33M5EnBqKSv9XJS5wEXhIJZOiWNrLktNEGl4boKXE7aNoRacreJhcE1UR6AOS7hPZ+6atwiePyF4mJUeb9HZtxa493wk9/Vv6BR9il++1Jz/QKX4oLef8hyBP4Rb60qgxirG7kBLR+j9zfhskCgYEAzA5y5xIeuIIU0H4XUDG9dcebxSSjbwsuYIgeLdb9pjMGQhsvjjyyoh8/nT20tLkJpkXN3FFCRjNnUWLRhWYrVkkh1wqWiYOPrwqh5MU4KN/sDWSPcznTY+drkTpMFoKzsvdrl2zf3VR3FneXKv742bkXj601Ykko+XWMHcLutisCgYBSq8IrsjzfaTQiTGI9a7WWsvzK92bq7Abnfq7swAXWcJd/bnjTQKLrrvt2bmwNvlWKAb3c69BFMn0X4t4PuN0iJQ39D6aQAEaM7HwWAmjf5TbodbmgbGxdsUB4xcCIQQ1mvTkigXWrCg0YAD2GZSoaslXAAVv6nR5qWEIa0Hx9GA=="
|
||||
)
|
||||
|
||||
func HideMyAssCountryChoices() (choices []string) {
|
||||
servers := HideMyAssServers()
|
||||
func HideMyAssCountryChoices(servers []models.HideMyAssServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -20,8 +19,7 @@ func HideMyAssCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func HideMyAssCityChoices() (choices []string) {
|
||||
servers := HideMyAssServers()
|
||||
func HideMyAssCityChoices(servers []models.HideMyAssServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -29,18 +27,10 @@ func HideMyAssCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func HideMyAssHostnameChoices() (choices []string) {
|
||||
servers := HideMyAssServers()
|
||||
func HideMyAssHostnameChoices(servers []models.HideMyAssServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// HideMyAssServers returns a slice of all the server information for HideMyAss.
|
||||
func HideMyAssServers() (servers []models.HideMyAssServer) {
|
||||
servers = make([]models.HideMyAssServer, len(allServers.HideMyAss.Servers))
|
||||
copy(servers, allServers.HideMyAss.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ const (
|
||||
IpvanishCA = "MIIErTCCA5WgAwIBAgIJAMYKzSS8uPKDMA0GCSqGSIb3DQEBDQUAMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCRkwxFDASBgNVBAcTC1dpbnRlciBQYXJrMREwDwYDVQQKEwhJUFZhbmlzaDEVMBMGA1UECxMMSVBWYW5pc2ggVlBOMRQwEgYDVQQDEwtJUFZhbmlzaCBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBpcHZhbmlzaC5jb20wHhcNMTIwMTExMTkzMjIwWhcNMjgxMTAyMTkzMjIwWjCBlTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkZMMRQwEgYDVQQHEwtXaW50ZXIgUGFyazERMA8GA1UEChMISVBWYW5pc2gxFTATBgNVBAsTDElQVmFuaXNoIFZQTjEUMBIGA1UEAxMLSVBWYW5pc2ggQ0ExIzAhBgkqhkiG9w0BCQEWFHN1cHBvcnRAaXB2YW5pc2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt9DBWNr/IKOuY3TmDP5x7vYZR0DGxLbXU8TyAzBbjUtFFMbhxlHiXVQrZHmgzih94x7BgXM7tWpmMKYVb+gNaqMdWE680Qm3nOwmhy/dulXDkEHAwD05i/iTx4ZaUdtV2vsKBxRg1vdC4AEiwD7bqV4HOi13xcG971aQ55Mj1KeCdA0aNvpat1LWx2jjWxsfI8s2Lv5Fkoi1HO1+vTnnaEsJZrBgAkLXpItqP29Lik3/OBIvkBIxlKrhiVPixE5qNiD+eSPirsmROvsyIonoJtuY4Dw5K6pcNlKyYiwo1IOFYU3YxffwFJk+bSW4WVBhsdf5dGxq/uOHmuz5gdwxCwIDAQABo4H9MIH6MAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFEv9FCWJHefBcIPX9p8RHCVOGe6uMIHKBgNVHSMEgcIwgb+AFEv9FCWJHefBcIPX9p8RHCVOGe6uoYGbpIGYMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCRkwxFDASBgNVBAcTC1dpbnRlciBQYXJrMREwDwYDVQQKEwhJUFZhbmlzaDEVMBMGA1UECxMMSVBWYW5pc2ggVlBOMRQwEgYDVQQDEwtJUFZhbmlzaCBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBpcHZhbmlzaC5jb22CCQDGCs0kvLjygzANBgkqhkiG9w0BAQ0FAAOCAQEAI2dkh/43ksV2fdYpVGhYaFZPVqCJoToCez0IvOmLeLGzow+EOSrY508oyjYeNP4VJEjApqo0NrMbKl8g/8bpLBcotOCF1c1HZ+y9v7648uumh01SMjsbBeHOuQcLb+7gX6c0pEmxWv8qj5JiW3/1L1bktnjW5Yp5oFkFSMXjOnIoYKHyKLjN2jtwH6XowUNYpg4qVtKU0CXPdOznWcd9/zSfa393HwJPeeVLbKYaFMC4IEbIUmKYtWyoJ9pJ58smU3pWsHZUg9Zc0LZZNjkNlBdQSLmUHAJ33Bd7pJS0JQeiWviC+4UTmzEWRKa7pDGnYRYNu2cUo0/voStphv8EVA=="
|
||||
)
|
||||
|
||||
func IpvanishCountryChoices() (choices []string) {
|
||||
servers := IpvanishServers()
|
||||
func IpvanishCountryChoices(servers []models.IpvanishServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -18,8 +17,7 @@ func IpvanishCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func IpvanishCityChoices() (choices []string) {
|
||||
servers := IpvanishServers()
|
||||
func IpvanishCityChoices(servers []models.IpvanishServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -27,18 +25,10 @@ func IpvanishCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func IpvanishHostnameChoices() (choices []string) {
|
||||
servers := IpvanishServers()
|
||||
func IpvanishHostnameChoices(servers []models.IpvanishServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// IpvanishServers returns a slice of all the server information for Ipvanish.
|
||||
func IpvanishServers() (servers []models.IpvanishServer) {
|
||||
servers = make([]models.IpvanishServer, len(allServers.Ipvanish.Servers))
|
||||
copy(servers, allServers.Ipvanish.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ const (
|
||||
IvpnOpenvpnStaticKeyV1 = "ac470c93ff9f5602a8aab37dee84a52814d10f20490ad23c47d5d82120c1bf859e93d0696b455d4a1b8d55d40c2685c41ca1d0aef29a3efd27274c4ef09020a3978fe45784b335da6df2d12db97bbb838416515f2a96f04715fd28949c6fe296a925cfada3f8b8928ed7fc963c1563272f5cf46e5e1d9c845d7703ca881497b7e6564a9d1dea9358adffd435295479f47d5298fabf5359613ff5992cb57ff081a04dfb81a26513a6b44a9b5490ad265f8a02384832a59cc3e075ad545461060b7bcab49bac815163cb80983dd51d5b1fd76170ffd904d8291071e96efc3fb777856c717b148d08a510f5687b8a8285dcffe737b98916dd15ef6235dee4266d3b"
|
||||
)
|
||||
|
||||
func IvpnCountryChoices() (choices []string) {
|
||||
servers := IvpnServers()
|
||||
func IvpnCountryChoices(servers []models.IvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -19,8 +18,7 @@ func IvpnCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func IvpnCityChoices() (choices []string) {
|
||||
servers := IvpnServers()
|
||||
func IvpnCityChoices(servers []models.IvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -28,18 +26,18 @@ func IvpnCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func IvpnHostnameChoices() (choices []string) {
|
||||
servers := IvpnServers()
|
||||
func IvpnISPChoices(servers []models.IvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].ISP
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func IvpnHostnameChoices(servers []models.IvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// IvpnServers returns a slice of all the server information for Ivpn.
|
||||
func IvpnServers() (servers []models.IvpnServer) {
|
||||
servers = make([]models.IvpnServer, len(allServers.Ivpn.Servers))
|
||||
copy(servers, allServers.Ivpn.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ const (
|
||||
MullvadCertificate = "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"
|
||||
)
|
||||
|
||||
func MullvadCountryChoices() (choices []string) {
|
||||
servers := MullvadServers()
|
||||
func MullvadCountryChoices(servers []models.MullvadServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -18,8 +17,7 @@ func MullvadCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func MullvadCityChoices() (choices []string) {
|
||||
servers := MullvadServers()
|
||||
func MullvadCityChoices(servers []models.MullvadServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -27,8 +25,7 @@ func MullvadCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func MullvadHostnameChoices() (choices []string) {
|
||||
servers := MullvadServers()
|
||||
func MullvadHostnameChoices(servers []models.MullvadServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
@@ -36,18 +33,10 @@ func MullvadHostnameChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func MullvadISPChoices() (choices []string) {
|
||||
servers := MullvadServers()
|
||||
func MullvadISPChoices(servers []models.MullvadServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].ISP
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// MullvadServers returns a slice of all the server information for Mullvad.
|
||||
func MullvadServers() (servers []models.MullvadServer) {
|
||||
servers = make([]models.MullvadServer, len(allServers.Mullvad.Servers))
|
||||
copy(servers, allServers.Mullvad.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ const (
|
||||
NordvpnOpenvpnStaticKeyV1 = "e685bdaf659a25a200e2b9e39e51ff030fc72cf1ce07232bd8b2be5e6c670143f51e937e670eee09d4f2ea5a6e4e69965db852c275351b86fc4ca892d78ae002d6f70d029bd79c4d1c26cf14e9588033cf639f8a74809f29f72b9d58f9b8f5fefc7938eade40e9fed6cb92184abb2cc10eb1a296df243b251df0643d53724cdb5a92a1d6cb817804c4a9319b57d53be580815bcfcb2df55018cc83fc43bc7ff82d51f9b88364776ee9d12fc85cc7ea5b9741c4f598c485316db066d52db4540e212e1518a9bd4828219e24b20d88f598a196c9de96012090e333519ae18d35099427e7b372d348d352dc4c85e18cd4b93f8a56ddb2e64eb67adfc9b337157ff4"
|
||||
)
|
||||
|
||||
func NordvpnRegionChoices() (choices []string) {
|
||||
servers := NordvpnServers()
|
||||
func NordvpnRegionChoices(servers []models.NordvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -19,27 +18,10 @@ func NordvpnRegionChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func NordvpnHostnameChoices() (choices []string) {
|
||||
servers := NordvpnServers()
|
||||
func NordvpnHostnameChoices(servers []models.NordvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func NordvpnNameChoices() (choices []string) {
|
||||
servers := NordvpnServers()
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Name
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// NordvpnServers returns a slice of all the server information for Nordvpn.
|
||||
func NordvpnServers() (servers []models.NordvpnServer) {
|
||||
servers = make([]models.NordvpnServer, len(allServers.Nordvpn.Servers))
|
||||
copy(servers, allServers.Nordvpn.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
21
internal/constants/perfectprivacy.go
Normal file
21
internal/constants/perfectprivacy.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
//nolint:lll
|
||||
const (
|
||||
PerfectprivacyCA = "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"
|
||||
PerfectprivacyCert = "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"
|
||||
PerfectprivacyPrivateKey = "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"
|
||||
PerfectprivacyTLSCryptOpenvpnStaticKeyV1 = "d10a8e2641f5834f6c5e04a6ee9a798553d338fa2836ef2a91057c1f6174a3a12b36f16d1110b20e42ae94d3bd579213e9c3770be6c74804348dddba876945a5a3ab7660f9436f85f331641f6efc81315f0d12b2766a9f15c10a53cf9ba32dc80f03b5f15a6cc6987bda795dbe83443ec81f3d5e161cd47fab6b1f125b3adeee1eae33370d018594e0ff6b25b815228d27371b32c82a95f4929d3abb5fa36e57bf1f42353542568fbb8233f4645f05820275f79570cb8bbcf8010fc5d20f07d031a8227d45daf7349e34158c91a3d4e5add19cfa02f683f87609f6525fa0594016d11abf2de649f83ad54edd3e74e032e34b1bca685b8499916826d9aee11c13"
|
||||
)
|
||||
|
||||
func PerfectprivacyCityChoices(servers []models.PerfectprivacyServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
@@ -15,8 +15,7 @@ const (
|
||||
PIACertificateStrong = "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"
|
||||
)
|
||||
|
||||
func PIAGeoChoices() (choices []string) {
|
||||
servers := PIAServers()
|
||||
func PIAGeoChoices(servers []models.PIAServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -24,8 +23,7 @@ func PIAGeoChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PIAHostnameChoices() (choices []string) {
|
||||
servers := PIAServers()
|
||||
func PIAHostnameChoices(servers []models.PIAServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
@@ -33,8 +31,7 @@ func PIAHostnameChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PIANameChoices() (choices []string) {
|
||||
servers := PIAServers()
|
||||
func PIANameChoices(servers []models.PIAServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].ServerName
|
||||
@@ -42,15 +39,8 @@ func PIANameChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// PIAServers returns a slice of all the server information for PIA.
|
||||
func PIAServers() (servers []models.PIAServer) {
|
||||
servers = make([]models.PIAServer, len(allServers.Pia.Servers))
|
||||
copy(servers, allServers.Pia.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
func PIAServerWhereName(serverName string) (server models.PIAServer) {
|
||||
for _, server := range PIAServers() {
|
||||
func PIAServerWhereName(servers []models.PIAServer, serverName string) (server models.PIAServer) {
|
||||
for _, server := range servers {
|
||||
if server.ServerName == serverName {
|
||||
return server
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
import "github.com/qdm12/gluetun/internal/models"
|
||||
|
||||
//nolint:lll
|
||||
const (
|
||||
PrivadoCertificate = "MIIFKDCCAxCgAwIBAgIJAMtrmqZxIV/OMA0GCSqGSIb3DQEBDQUAMBIxEDAOBgNVBAMMB1ByaXZhZG8wHhcNMjAwMTA4MjEyODQ1WhcNMzUwMTA5MjEyODQ1WjASMRAwDgYDVQQDDAdQcml2YWRvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxPwOgiwNJzZTnKIXwAB0TSu/Lu2qt2U2I8obtQjwhi/7OrfmbmYykSdro70al2XPhnwAGGdCxW6LDnp0UN/IOhD11mgBPo14f5CLkBQjSJ6VN5miPbvK746LsNZl9H8rQGvDuPo4CG9BfPZMiDRGlsMxij/jztzgT1gmuxQ7WHfFRcNzBas1dHa9hV/d3TU6/t47x4SE/ljdcCtJiu7Zn6ODKQoys3mB7Luz2ngqUJWvkqsg+E4+3eJ0M8Hlbn5TPaRJBID7DAdYo6Vs6xGCYr981ThFcmoIQ10js10yANrrfGAzd03b3TnLAgko0uQMHjliMZL6L8sWOPHxyxJI0us88SFh4UgcFyRHKHPKux7w24SxAlZUYoUcTHp9VjG5XvDKYxzgV2RdM4ulBGbQRQ3y3/CyddsyQYMvA55Ets0LfPaBvDIcct70iXijGsdvlX1du3ArGpG7Vaje/RU4nbbGT6HYRdt5YyZfof288ukMOSj20nVcmS+c/4tqsxSerRb1aq5LOi1IemSkTMeC5gCbexk+L1vl7NT/58sxjGmu5bXwnvev/lIItfi2AlITrfUSEv19iDMKkeshwn/+sFJBMWYyluP+yJ56yR+MWoXvLlSWphLDTqq19yx3BZn0P1tgbXoR0g8PTdJFcz8z3RIb7myVLYulV1oGG/3rka0CAwEAAaOBgDB+MB0GA1UdDgQWBBTFtJkZCVDuDAD6k5bJzefjJdO3DTBCBgNVHSMEOzA5gBTFtJkZCVDuDAD6k5bJzefjJdO3DaEWpBQwEjEQMA4GA1UEAwwHUHJpdmFkb4IJAMtrmqZxIV/OMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBDQUAA4ICAQB7MUSXMeBb9wlSv4sUaT1JHEwE26nlBw+TKmezfuPU5pBlY0LYr6qQZY95DHqsRJ7ByUzGUrGo17dNGXlcuNc6TAaQQEDRPo6y+LVh2TWMk15TUMI+MkqryJtCret7xGvDigKYMJgBy58HN3RAVr1B7cL9youwzLgc2Y/NcFKvnQJKeiIYAJ7g0CcnJiQvgZTS7xdwkEBXfsngmUCIG320DLPEL+Ze0HiUrxwWljMRya6i40AeH3Zu2i532xX1wV5+cjA4RJWIKg6ri/Q54iFGtZrA9/nc6y9uoQHkmz8cGyVUmJxFzMrrIICVqUtVRxLhkTMe4UzwRWTBeGgtW4tS0yq1QonAKfOyjgRw/CeY55D2UGvnAFZdTadtYXS4Alu2P9zdwoEk3fzHiVmDjqfJVr5wz9383aABUFrPI3nz6ed/Z6LZflKh1k+DUDEp8NxU4klUULWsSOKoa5zGX51G8cdHxwQLImXvtGuN5eSR8jCTgxFZhdps/xes4KkyfIz9FMYG748M+uOTgKITf4zdJ9BAyiQaOufVQZ8WjhWzWk9YHec9VqPkzpWNGkVjiRI5ewuXwZzZ164tMv2hikBXSuUCnFz37/ZNwGlDi0oBdDszCk2GxccdFHHaCSmpjU5MrdJ+5IhtTKGeTx+US2hTIVHQFIO99DmacxSYvLNcSQ=="
|
||||
)
|
||||
|
||||
func PrivadoCountryChoices() (choices []string) {
|
||||
servers := PrivadoServers()
|
||||
func PrivadoCountryChoices(servers []models.PrivadoServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -18,8 +15,7 @@ func PrivadoCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PrivadoRegionChoices() (choices []string) {
|
||||
servers := PrivadoServers()
|
||||
func PrivadoRegionChoices(servers []models.PrivadoServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -27,8 +23,7 @@ func PrivadoRegionChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PrivadoCityChoices() (choices []string) {
|
||||
servers := PrivadoServers()
|
||||
func PrivadoCityChoices(servers []models.PrivadoServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -36,18 +31,10 @@ func PrivadoCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PrivadoHostnameChoices() (choices []string) {
|
||||
servers := PrivadoServers()
|
||||
func PrivadoHostnameChoices(servers []models.PrivadoServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// PrivadoServers returns a slice of all the Privado servers.
|
||||
func PrivadoServers() (servers []models.PrivadoServer) {
|
||||
servers = make([]models.PrivadoServer, len(allServers.Privado.Servers))
|
||||
copy(servers, allServers.Privado.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
import "github.com/qdm12/gluetun/internal/models"
|
||||
|
||||
//nolint:lll
|
||||
const (
|
||||
PrivatevpnCertificate = "MIIErTCCA5WgAwIBAgIJAPp3HmtYGCIOMA0GCSqGSIb3DQEBCwUAMIGVMQswCQYDVQQGEwJTRTELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVN0b2NraG9sbTETMBEGA1UEChMKUHJpdmF0ZVZQTjEWMBQGA1UEAxMNUHJpdmF0ZVZQTiBDQTETMBEGA1UEKRMKUHJpdmF0ZVZQTjEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBwcml2YXR2cG4uc2UwHhcNMTcwNTI0MjAxNTM3WhcNMjcwNTIyMjAxNTM3WjCBlTELMAkGA1UEBhMCU0UxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlTdG9ja2hvbG0xEzARBgNVBAoTClByaXZhdGVWUE4xFjAUBgNVBAMTDVByaXZhdGVWUE4gQ0ExEzARBgNVBCkTClByaXZhdGVWUE4xIzAhBgkqhkiG9w0BCQEWFHN1cHBvcnRAcHJpdmF0dnBuLnNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwjqTWbKk85WN8nd1TaBgBnBHceQWosp8mMHr4xWMTLagWRcq2Modfy7RPnBo9kyn5j/ZZwL/21gLWJbxidurGyZZdEV9Wb5KQl3DUNxa19kwAbkkEchdES61e99MjmQlWq4vGPXAHjEuDxOZ906AXglCyAvQoXcYW0mNm9yybWllVp1aBrCaZQrNYr7eoFvolqJXdQQ3FFsTBCYa5bHJcKQLBfsiqdJ/BAxhNkQtcmWNSgLy16qoxQpCsxNCxAcYnasuL4rwOP+RazBkJTPXA/2neCJC5rt+sXR9CSfiXdJGwMpYso5m31ZEd7JL2+is0FeAZ6ETrKMnEZMsTpTkdwIDAQABo4H9MIH6MB0GA1UdDgQWBBRCkBlC94zCY6VNncMnK36JxT7bazCBygYDVR0jBIHCMIG/gBRCkBlC94zCY6VNncMnK36JxT7ba6GBm6SBmDCBlTELMAkGA1UEBhMCU0UxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlTdG9ja2hvbG0xEzARBgNVBAoTClByaXZhdGVWUE4xFjAUBgNVBAMTDVByaXZhdGVWUE4gQ0ExEzARBgNVBCkTClByaXZhdGVWUE4xIzAhBgkqhkiG9w0BCQEWFHN1cHBvcnRAcHJpdmF0dnBuLnNlggkA+ncea1gYIg4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAayugvExKDHar7t1zyYn99Vt1NMf46J8x4Dt9TNjBml5mR9nKvWmreMUuuOhLaO8Da466KGdXeDFNLcBYZd/J2iTawE6/3fmrML9H2sa+k/+E4uU5nQ84ZGOwCinCkMalVjM8EZ0/H2RZvLAVUnvPuUz2JfJhmiRkbeE75fVuqpAm9qdE+/7lg3oICYzxa6BJPxT+Imdjy3Q/FWdsXqX6aallhohPAZlMZgZL4eXECnV8rAfzyjOJggkMDZQt3Flc0Y4iDMfzrEhSOWMkNFBFwjK0F/dnhsX+fPX6GGRpUZgZcCt/hWvypqc05/SnrdKM/vV/jV/yZe0NVzY7S8Ur5g=="
|
||||
PrivatevpnOpenvpnStaticKeyV1 = "a49082f082ca89d6a6bb4ecc7c047c6d428a1d3c8254a95206d38a61d7fbe65984214cd7d56eacc5a60803bffd677fa7294d4bfe555036339312de2dfb1335bd9d5fd94b04bba3a15fc5192aeb02fb6d8dd2ca831fad7509be5eefa8d1eaa689dc586c831a23b589c512662652ecf1bb3a4a673816aba434a04f6857b8c2f8bb265bfe48a7b8112539729d2f7d9734a720e1035188118c73fef1824d0237d5579ca382d703b4bb252acaedc753b12199f00154d3769efbcf85ef5ad6ee755cbeaa944cb98e7654286df54c793a8443f5363078e3da548ba0beed079df633283cefb256f6a4bcfc4ab2c4affc24955c1864d5458e84a7c210d0d186269e55dcf6"
|
||||
PrivatevpnOpenvpnStaticKeyV1 = "f035a3acaeffb5aedb5bc920bca26ca7ac701da88249008e03563eba6af6d2625ac8ba1e5e0921f76be004c24ae4fd43e42caf0f84269ad44d8d4c14ba45b1386f251c7330d8cc56afd16d516835645651ef7e87a723ac78ae0d49da5b2f2d78ceafcff7a6367d0712628a6547e5fc8fef93c87f7bcd6107c7b1ae68396e944aadae50111d01a5d0c67223d667bdbf1bf434bdef03644ecc5386e102724eef3872f66547eb66dc0fea8286069cb082a41c89083b28fe9f4cec25d48017f26c4fd85b25ddf2ae5448dd2bccf3eef2aacf42ef1e88c3248c689423d0b05a641e9e79dd6b9b5c40f0cc21ffdc891b9eee951477b537261cb56a958a4f490d961ecb"
|
||||
)
|
||||
|
||||
func PrivatevpnCountryChoices() (choices []string) {
|
||||
servers := PrivatevpnServers()
|
||||
func PrivatevpnCountryChoices(servers []models.PrivatevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -19,8 +16,7 @@ func PrivatevpnCountryChoices() (choices []string) {
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func PrivatevpnCityChoices() (choices []string) {
|
||||
servers := PrivatevpnServers()
|
||||
func PrivatevpnCityChoices(servers []models.PrivatevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -28,17 +24,10 @@ func PrivatevpnCityChoices() (choices []string) {
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func PrivatevpnHostnameChoices() (choices []string) {
|
||||
servers := PrivatevpnServers()
|
||||
func PrivatevpnHostnameChoices(servers []models.PrivatevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func PrivatevpnServers() (servers []models.PrivatevpnServer) {
|
||||
servers = make([]models.PrivatevpnServer, len(allServers.Privatevpn.Servers))
|
||||
copy(servers, allServers.Privatevpn.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
import "github.com/qdm12/gluetun/internal/models"
|
||||
|
||||
//nolint:lll
|
||||
const (
|
||||
@@ -10,8 +8,7 @@ const (
|
||||
ProtonvpnOpenvpnStaticKeyV1 = "6acef03f62675b4b1bbd03e53b187727423cea742242106cb2916a8a4c8297563d22c7e5cef430b1103c6f66eb1fc5b375a672f158e2e2e936c3faa48b035a6de17beaac23b5f03b10b868d53d03521d8ba115059da777a60cbfd7b2c9c5747278a15b8f6e68a3ef7fd583ec9f398c8bd4735dab40cbd1e3c62a822e97489186c30a0b48c7c38ea32ceb056d3fa5a710e10ccc7a0ddb363b08c3d2777a3395e10c0b6080f56309192ab5aacd4b45f55da61fc77af39bd81a19218a79762c33862df55785075f37d8c71dc8a42097ee43344739a0dd48d03025b0450cf1fb5e8caeb893d9a96d1f15519bb3c4dcb40ee316672ea16c012664f8a9f11255518deb"
|
||||
)
|
||||
|
||||
func ProtonvpnCountryChoices() (choices []string) {
|
||||
servers := ProtonvpnServers()
|
||||
func ProtonvpnCountryChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -19,8 +16,7 @@ func ProtonvpnCountryChoices() (choices []string) {
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func ProtonvpnRegionChoices() (choices []string) {
|
||||
servers := ProtonvpnServers()
|
||||
func ProtonvpnRegionChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -28,8 +24,7 @@ func ProtonvpnRegionChoices() (choices []string) {
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func ProtonvpnCityChoices() (choices []string) {
|
||||
servers := ProtonvpnServers()
|
||||
func ProtonvpnCityChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -37,8 +32,7 @@ func ProtonvpnCityChoices() (choices []string) {
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func ProtonvpnNameChoices() (choices []string) {
|
||||
servers := ProtonvpnServers()
|
||||
func ProtonvpnNameChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Name
|
||||
@@ -46,18 +40,10 @@ func ProtonvpnNameChoices() (choices []string) {
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func ProtonvpnHostnameChoices() (choices []string) {
|
||||
servers := ProtonvpnServers()
|
||||
func ProtonvpnHostnameChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
// ProtonvpnServers returns a slice of all the server information for Protonvpn.
|
||||
func ProtonvpnServers() (servers []models.ProtonvpnServer) {
|
||||
servers = make([]models.ProtonvpnServer, len(allServers.Protonvpn.Servers))
|
||||
copy(servers, allServers.Protonvpn.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
import "github.com/qdm12/gluetun/internal/models"
|
||||
|
||||
//nolint:lll
|
||||
const (
|
||||
@@ -12,8 +10,7 @@ const (
|
||||
PurevpnOpenvpnStaticKeyV1 = "e30af995f56d07426d9ba1f824730521d4283db4b4d0cdda9c6e8759a3799dcb7939b6a5989160c9660de0f6125cbb1f585b41c074b2fe88ecfcf17eab9a33be1352379cdf74952b588fb161a93e13df9135b2b29038231e02d657a6225705e6868ccb0c384ed11614690a1894bfbeb274cebf1fe9c2329bdd5c8a40fe8820624d2ea7540cd79ab76892db51fc371a3ac5fc9573afecb3fffe3281e61d72e91579d9b03d8cbf7909b3aebf4d90850321ee6b7d0a7846d15c27d8290e031e951e19438a4654663cad975e138f5bc5af89c737ad822f27e19057731f41e1e254cc9c95b7175c622422cde9f1f2cfd3510add94498b4d7133d3729dd214a16b27fb"
|
||||
)
|
||||
|
||||
func PurevpnRegionChoices() (choices []string) {
|
||||
servers := PurevpnServers()
|
||||
func PurevpnRegionChoices(servers []models.PurevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -21,8 +18,7 @@ func PurevpnRegionChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PurevpnCountryChoices() (choices []string) {
|
||||
servers := PurevpnServers()
|
||||
func PurevpnCountryChoices(servers []models.PurevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -30,8 +26,7 @@ func PurevpnCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PurevpnCityChoices() (choices []string) {
|
||||
servers := PurevpnServers()
|
||||
func PurevpnCityChoices(servers []models.PurevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -39,18 +34,10 @@ func PurevpnCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PurevpnHostnameChoices() (choices []string) {
|
||||
servers := PurevpnServers()
|
||||
func PurevpnHostnameChoices(servers []models.PurevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// PurevpnServers returns a slice of all the server information for Purevpn.
|
||||
func PurevpnServers() (servers []models.PurevpnServer) {
|
||||
servers = make([]models.PurevpnServer, len(allServers.Purevpn.Servers))
|
||||
copy(servers, allServers.Purevpn.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"sync"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
//go:embed servers.json
|
||||
var allServersEmbedFS embed.FS //nolint:gochecknoglobals
|
||||
var allServers models.AllServers //nolint:gochecknoglobals
|
||||
var parseOnce sync.Once //nolint:gochecknoglobals
|
||||
|
||||
func init() { //nolint:gochecknoinits
|
||||
// error returned covered by unit test
|
||||
parseOnce.Do(func() { allServers, _ = parseAllServers() })
|
||||
}
|
||||
|
||||
func parseAllServers() (allServers models.AllServers, err error) {
|
||||
f, err := allServersEmbedFS.Open("servers.json")
|
||||
if err != nil {
|
||||
return allServers, err
|
||||
}
|
||||
decoder := json.NewDecoder(f)
|
||||
err = decoder.Decode(&allServers)
|
||||
return allServers, err
|
||||
}
|
||||
|
||||
func GetAllServers() models.AllServers {
|
||||
parseOnce.Do(func() { allServers, _ = parseAllServers() }) // init did not execute, used in tests
|
||||
return allServers
|
||||
}
|
||||
@@ -10,8 +10,7 @@ const (
|
||||
SurfsharkOpenvpnStaticKeyV1 = "b02cb1d7c6fee5d4f89b8de72b51a8d0c7b282631d6fc19be1df6ebae9e2779e6d9f097058a31c97f57f0c35526a44ae09a01d1284b50b954d9246725a1ead1ff224a102ed9ab3da0152a15525643b2eee226c37041dc55539d475183b889a10e18bb94f079a4a49888da566b99783460ece01daaf93548beea6c827d9674897e7279ff1a19cb092659e8c1860fbad0db4ad0ad5732f1af4655dbd66214e552f04ed8fd0104e1d4bf99c249ac229ce169d9ba22068c6c0ab742424760911d4636aafb4b85f0c952a9ce4275bc821391aa65fcd0d2394f006e3fba0fd34c4bc4ab260f4b45dec3285875589c97d3087c9134d3a3aa2f904512e85aa2dc2202498"
|
||||
)
|
||||
|
||||
func SurfsharkRegionChoices() (choices []string) {
|
||||
servers := SurfsharkServers()
|
||||
func SurfsharkRegionChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -19,18 +18,211 @@ func SurfsharkRegionChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func SurfsharkHostnameChoices() (choices []string) {
|
||||
servers := SurfsharkServers()
|
||||
func SurfsharkCountryChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func SurfsharkCityChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// TODO remove in v4.
|
||||
func SurfsharkRetroLocChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||
locationData := SurfsharkLocationData()
|
||||
choices = make([]string, len(locationData))
|
||||
for i := range locationData {
|
||||
choices[i] = locationData[i].RetroLoc
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func SurfsharkHostToLocation() (hostToLocation map[string]models.SurfsharkLocationData) {
|
||||
locationData := SurfsharkLocationData()
|
||||
hostToLocation = make(map[string]models.SurfsharkLocationData, len(locationData))
|
||||
for _, data := range locationData {
|
||||
hostToLocation[data.Hostname] = data
|
||||
}
|
||||
return hostToLocation
|
||||
}
|
||||
|
||||
// TODO remove retroRegion and servers from API in v4.
|
||||
func SurfsharkLocationData() (data []models.SurfsharkLocationData) {
|
||||
//nolint:lll
|
||||
return []models.SurfsharkLocationData{
|
||||
{Region: "Asia Pacific", Country: "Australia", City: "Adelaide", RetroLoc: "Australia Adelaide", Hostname: "au-adl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Australia", City: "Brisbane", RetroLoc: "Australia Brisbane", Hostname: "au-bne.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Australia", City: "Melbourne", RetroLoc: "Australia Melbourne", Hostname: "au-mel.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Australia", City: "Perth", RetroLoc: "Australia Perth", Hostname: "au-per.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Australia", City: "Sydney", RetroLoc: "Australia Sydney", Hostname: "au-syd.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Azerbaijan", City: "Baku", RetroLoc: "Azerbaijan", Hostname: "az-bak.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Hong Kong", City: "Hong Kong", RetroLoc: "Hong Kong", Hostname: "hk-hkg.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "India", City: "Chennai", RetroLoc: "India Chennai", Hostname: "in-chn.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "India", City: "Indore", RetroLoc: "India Indore", Hostname: "in-idr.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "India", City: "Mumbai", RetroLoc: "India Mumbai", Hostname: "in-mum.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Indonesia", City: "Jakarta", RetroLoc: "Indonesia", Hostname: "id-jak.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st001", Hostname: "jp-tok-st001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st002", Hostname: "jp-tok-st002.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st003", Hostname: "jp-tok-st003.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st004", Hostname: "jp-tok-st004.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st005", Hostname: "jp-tok-st005.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st006", Hostname: "jp-tok-st006.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st007", Hostname: "jp-tok-st007.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st008", Hostname: "jp-tok-st008.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st009", Hostname: "jp-tok-st009.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st010", Hostname: "jp-tok-st010.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st011", Hostname: "jp-tok-st011.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st012", Hostname: "jp-tok-st012.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st013", Hostname: "jp-tok-st013.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo", Hostname: "jp-tok.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Kazakhstan", City: "Oral", RetroLoc: "Kazakhstan", Hostname: "kz-ura.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Malaysia", City: "Kuala Lumpur", RetroLoc: "Malaysia", Hostname: "my-kul.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "New Zealand", City: "Auckland", RetroLoc: "New Zealand", Hostname: "nz-akl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Philippines", City: "Manila", RetroLoc: "Philippines", Hostname: "ph-mnl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Singapore Hong Kong", City: "Hong Kong", RetroLoc: "Singapore Hong Kong", Hostname: "sg-hk.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Asia Pacific", Country: "Singapore in", City: "", RetroLoc: "Singapore in", Hostname: "sg-in.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore mp001", Hostname: "sg-sng-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore st001", Hostname: "sg-sng-st001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore st002", Hostname: "sg-sng-st002.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore st003", Hostname: "sg-sng-st003.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore st004", Hostname: "sg-sng-st004.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore", Hostname: "sg-sng.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "South Korea", City: "Seoul", RetroLoc: "Korea", Hostname: "kr-seo.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Taiwan", City: "Taichung City", RetroLoc: "Taiwan", Hostname: "tw-tai.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Thailand", City: "Bangkok", RetroLoc: "Thailand", Hostname: "th-bkk.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Vietnam", City: "Ho Chi Minh City", RetroLoc: "Vietnam", Hostname: "vn-hcm.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Albania", City: "Tirana", RetroLoc: "Albania", Hostname: "al-tia.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Austria", City: "Vienna", RetroLoc: "Austria", Hostname: "at-vie.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Belgium", City: "Brussels", RetroLoc: "Belgium", Hostname: "be-bru.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Bosnia and Herzegovina", City: "Sarajevo", RetroLoc: "Bosnia and Herzegovina", Hostname: "ba-sjj.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Bulgaria", City: "Sofia", RetroLoc: "Bulgaria", Hostname: "bg-sof.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Croatia", City: "Zagreb", RetroLoc: "Croatia", Hostname: "hr-zag.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Cyprus", City: "Nicosia", RetroLoc: "Cyprus", Hostname: "cy-nic.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Czech Republic", City: "Prague", RetroLoc: "Czech Republic", Hostname: "cz-prg.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Denmark", City: "Copenhagen", RetroLoc: "Denmark", Hostname: "dk-cph.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Estonia", City: "Tallinn", RetroLoc: "Estonia", Hostname: "ee-tll.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Finland", City: "Helsinki", RetroLoc: "Finland", Hostname: "fi-hel.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "France Sweden", City: "", RetroLoc: "France Sweden", Hostname: "fr-se.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "France", City: "Bordeaux", RetroLoc: "France Bordeaux", Hostname: "fr-bod.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "France", City: "Marseille", RetroLoc: "France Marseilles", Hostname: "fr-mrs.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "France", City: "Paris", RetroLoc: "France Paris", Hostname: "fr-par.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany Singapour", City: "", RetroLoc: "Germany Singapour", Hostname: "de-sg.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "Germany UK", City: "", RetroLoc: "Germany UK", Hostname: "de-uk.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "Germany", City: "Berlin", RetroLoc: "Germany Berlin", Hostname: "de-ber.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st001", Hostname: "de-fra-st001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st002", Hostname: "de-fra-st002.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st003", Hostname: "de-fra-st003.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st004", Hostname: "de-fra-st004.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st005", Hostname: "de-fra-st005.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main", Hostname: "de-fra.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt mp001", Hostname: "de-fra-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Greece", City: "Athens", RetroLoc: "Greece", Hostname: "gr-ath.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Hungary", City: "Budapest", RetroLoc: "Hungary", Hostname: "hu-bud.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Iceland", City: "Reykjavik", RetroLoc: "Iceland", Hostname: "is-rkv.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "India UK", City: "", RetroLoc: "India UK", Hostname: "in-uk.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "Ireland", City: "Dublin", RetroLoc: "Ireland", Hostname: "ie-dub.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Italy", City: "Milan", RetroLoc: "Italy Milan", Hostname: "it-mil.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Italy", City: "Rome", RetroLoc: "Italy Rome", Hostname: "it-rom.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Latvia", City: "Riga", RetroLoc: "Latvia", Hostname: "lv-rig.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Luxembourg", City: "Luxembourg", RetroLoc: "Luxembourg", Hostname: "lu-ste.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Moldova", City: "Chisinau", RetroLoc: "Moldova", Hostname: "md-chi.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Netherlands", City: "Amsterdam", RetroLoc: "Netherlands Amsterdam mp001", Hostname: "nl-ams-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Netherlands", City: "Amsterdam", RetroLoc: "Netherlands Amsterdam st001", Hostname: "nl-ams-st001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Netherlands", City: "Amsterdam", RetroLoc: "Netherlands Amsterdam", Hostname: "nl-ams.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "North Macedonia", City: "Skopje", RetroLoc: "North Macedonia", Hostname: "mk-skp.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Norway", City: "Oslo", RetroLoc: "Norway", Hostname: "no-osl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Poland", City: "Gdansk", RetroLoc: "Poland Gdansk", Hostname: "pl-gdn.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Poland", City: "Warsaw", RetroLoc: "Poland Warsaw", Hostname: "pl-waw.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Portugal", City: "Lisbon", RetroLoc: "Portugal Lisbon", Hostname: "pt-lis.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Portugal", City: "Porto", RetroLoc: "Portugal Porto", Hostname: "pt-opo.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Romania", City: "Bucharest", RetroLoc: "Romania", Hostname: "ro-buc.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Russia", City: "Moscow", RetroLoc: "Russia Moscow", Hostname: "ru-mos.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Serbia", City: "Belgrade", RetroLoc: "Serbia", Hostname: "rs-beg.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Singapore Netherlands", City: "", RetroLoc: "Singapore Netherlands", Hostname: "sg-nl.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "Slovakia", City: "Bratislava", RetroLoc: "Slovekia", Hostname: "sk-bts.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Slovenia", City: "Ljubljana", RetroLoc: "Slovenia", Hostname: "si-lju.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Spain", City: "Barcelona", RetroLoc: "Spain Barcelona", Hostname: "es-bcn.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Spain", City: "Madrid", RetroLoc: "Spain Madrid", Hostname: "es-mad.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Spain", City: "Valencia", RetroLoc: "Spain Valencia", Hostname: "es-vlc.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Sweden", City: "Stockholm", RetroLoc: "Sweden", Hostname: "se-sto.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Switzerland", City: "Zurich", RetroLoc: "Switzerland", Hostname: "ch-zur.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Turkey", City: "Istanbul", RetroLoc: "Turkey Istanbul", Hostname: "tr-ist.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "UK France", City: "", RetroLoc: "UK France", Hostname: "uk-fr.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "UK Germany", City: "", RetroLoc: "UK Germany", Hostname: "uk-de.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "Ukraine", City: "Kyiv", RetroLoc: "Ukraine", Hostname: "ua-iev.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "Glasgow", RetroLoc: "UK Glasgow", Hostname: "uk-gla.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London mp001", Hostname: "uk-lon-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st001", Hostname: "uk-lon-st001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st002", Hostname: "uk-lon-st002.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st003", Hostname: "uk-lon-st003.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st004", Hostname: "uk-lon-st004.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st005", Hostname: "uk-lon-st005.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London", Hostname: "uk-lon.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "Manchester", RetroLoc: "UK Manchester", Hostname: "uk-man.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "US Netherlands", City: "", RetroLoc: "US Netherlands", Hostname: "us-nl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "US Portugal", City: "", RetroLoc: "US Portugal", Hostname: "us-pt.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Middle East and Africa", Country: "Israel", City: "Tel Aviv", RetroLoc: "Israel", Hostname: "il-tlv.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Middle East and Africa", Country: "Nigeria", City: "Lagos", RetroLoc: "Nigeria", Hostname: "ng-lag.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Middle East and Africa", Country: "South Africa", City: "Johannesburg", RetroLoc: "South Africa", Hostname: "za-jnb.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Middle East and Africa", Country: "United Arab Emirates", City: "Dubai", RetroLoc: "United Arab Emirates", Hostname: "ae-dub.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Argentina", City: "Buenos Aires", RetroLoc: "Argentina Buenos Aires", Hostname: "ar-bua.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Australia US", City: "", RetroLoc: "Australia US", Hostname: "au-us.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "The Americas", Country: "Brazil", City: "Sao Paulo", RetroLoc: "Brazil", Hostname: "br-sao.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Canada US", City: "", RetroLoc: "Canada US", Hostname: "ca-us.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "The Americas", Country: "Canada", City: "Montreal", RetroLoc: "Canada Montreal", Hostname: "ca-mon.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Canada", City: "Toronto", RetroLoc: "Canada Toronto mp001", Hostname: "ca-tor-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Canada", City: "Toronto", RetroLoc: "Canada Toronto", Hostname: "ca-tor.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Canada", City: "Vancouver", RetroLoc: "Canada Vancouver", Hostname: "ca-van.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Chile", City: "Santiago", RetroLoc: "Chile", Hostname: "cl-san.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Colombia", City: "Bogota", RetroLoc: "Colombia", Hostname: "co-bog.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Costa Rica", City: "San Jose", RetroLoc: "Costa Rica", Hostname: "cr-sjn.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Mexico", City: "Mexico City", RetroLoc: "Mexico City Mexico", Hostname: "mx-mex.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Netherlands US", City: "", RetroLoc: "Netherlands US", Hostname: "nl-us.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "The Americas", Country: "United States", City: "Atlanta", RetroLoc: "US Atlanta", Hostname: "us-atl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Bend", RetroLoc: "US Bend", Hostname: "us-bdn.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Boston", RetroLoc: "US Boston", Hostname: "us-bos.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Buffalo", RetroLoc: "US Buffalo", Hostname: "us-buf.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Charlotte", RetroLoc: "US Charlotte", Hostname: "us-clt.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Chicago", RetroLoc: "US Chicago", Hostname: "us-chi.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Dallas", RetroLoc: "US Dallas", Hostname: "us-dal.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Denver", RetroLoc: "US Denver", Hostname: "us-den.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Detroit", RetroLoc: "US Gahanna", Hostname: "us-dtw.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Houston", RetroLoc: "US Houston", Hostname: "us-hou.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Kansas City", RetroLoc: "US Kansas City", Hostname: "us-kan.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Las Vegas", RetroLoc: "US Las Vegas", Hostname: "us-las.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Latham", RetroLoc: "US Latham", Hostname: "us-ltm.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Los Angeles", RetroLoc: "US Los Angeles", Hostname: "us-lax.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Manassas", RetroLoc: "US Maryland", Hostname: "us-mnz.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Miami", RetroLoc: "US Miami", Hostname: "us-mia.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City mp001", Hostname: "us-nyc-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st001", Hostname: "us-nyc-st001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st002", Hostname: "us-nyc-st002.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st003", Hostname: "us-nyc-st003.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st004", Hostname: "us-nyc-st004.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st005", Hostname: "us-nyc-st005.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City", Hostname: "us-nyc.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Orlando", RetroLoc: "US Orlando", Hostname: "us-orl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Phoenix", RetroLoc: "US Phoenix", Hostname: "us-phx.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Salt Lake City", RetroLoc: "US Salt Lake City", Hostname: "us-slc.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "San Francisco", RetroLoc: "US San Francisco mp001", Hostname: "us-sfo-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "San Francisco", RetroLoc: "US San Francisco", Hostname: "us-sfo.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Seattle", RetroLoc: "US Seatle", Hostname: "us-sea.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "St. Louis", RetroLoc: "US Saint Louis", Hostname: "us-stl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Tampa", RetroLoc: "US Tampa", Hostname: "us-tpa.prod.surfshark.com", MultiHop: false},
|
||||
}
|
||||
}
|
||||
|
||||
func SurfsharkHostnameChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// SurfsharkServers returns a slice of all the server information for Surfshark.
|
||||
func SurfsharkServers() (servers []models.SurfsharkServer) {
|
||||
servers = make([]models.SurfsharkServer, len(allServers.Surfshark.Servers))
|
||||
copy(servers, allServers.Surfshark.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ const (
|
||||
TorguardOpenvpnStaticKeyV1 = "770e8de5fc56e0248cc7b5aab56be80d0e19cbf003c1b3ed68efbaf08613c3a1a019dac6a4b84f13a6198f73229ffc21fa512394e288f82aa2cf0180f01fb3eb1a71e00a077a20f6d7a83633f5b4f47f27e30617eaf8485dd8c722a8606d56b3c183f65da5d3c9001a8cbdb96c793d936251098b24fe52a6dd2472e98cfccbc466e63520d63ade7a0eacc36208c3142a1068236a52142fbb7b3ed83d785e12a28261bccfb3bcb62a8d2f6d18f5df5f3652e59c5627d8d9c8f7877c4d7b08e19a5c363556ba68d392be78b75152dd55ba0f74d45089e84f77f4492d886524ea6c82b9f4dd83d46528d4f5c3b51cfeaf2838d938bd0597c426b0e440434f2c451f"
|
||||
)
|
||||
|
||||
func TorguardCountryChoices() (choices []string) {
|
||||
servers := TorguardServers()
|
||||
func TorguardCountryChoices(servers []models.TorguardServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -19,8 +18,7 @@ func TorguardCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func TorguardCityChoices() (choices []string) {
|
||||
servers := TorguardServers()
|
||||
func TorguardCityChoices(servers []models.TorguardServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -28,18 +26,10 @@ func TorguardCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func TorguardHostnameChoices() (choices []string) {
|
||||
servers := TorguardServers()
|
||||
func TorguardHostnameChoices(servers []models.TorguardServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// TorguardServers returns a slice of all the server information for Torguard.
|
||||
func TorguardServers() (servers []models.TorguardServer) {
|
||||
servers = make([]models.TorguardServer, len(allServers.Torguard.Servers))
|
||||
copy(servers, allServers.Torguard.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -6,8 +6,13 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
// Custom is the VPN provider name for custom
|
||||
// VPN configurations.
|
||||
Custom = "custom"
|
||||
// Cyberghost is a VPN provider.
|
||||
Cyberghost = "cyberghost"
|
||||
// Expressvpn is a VPN provider.
|
||||
Expressvpn = "expressvpn"
|
||||
// Fastestvpn is a VPN provider.
|
||||
Fastestvpn = "fastestvpn"
|
||||
// HideMyAss is a VPN provider.
|
||||
@@ -20,6 +25,8 @@ const (
|
||||
Mullvad = "mullvad"
|
||||
// Nordvpn is a VPN provider.
|
||||
Nordvpn = "nordvpn"
|
||||
// Perfectprivacy is a VPN provider.
|
||||
Perfectprivacy = "perfect privacy"
|
||||
// Privado is a VPN provider.
|
||||
Privado = "privado"
|
||||
// PrivateInternetAccess is a VPN provider.
|
||||
@@ -38,6 +45,8 @@ const (
|
||||
VPNUnlimited = "vpn unlimited"
|
||||
// Vyprvpn is a VPN provider.
|
||||
Vyprvpn = "vyprvpn"
|
||||
// WeVPN is a VPN provider.
|
||||
Wevpn = "wevpn"
|
||||
// Windscribe is a VPN provider.
|
||||
Windscribe = "windscribe"
|
||||
)
|
||||
|
||||
@@ -9,8 +9,7 @@ const (
|
||||
VPNUnlimitedCertificateAuthority = "MIIEjjCCA/egAwIBAgIJAKsVbHBdakXuMA0GCSqGSIb3DQEBBQUAMIHgMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTlkxETAPBgNVBAcTCE5ldyBZb3JrMR8wHQYDVQQKExZTaW1wbGV4IFNvbHV0aW9ucyBJbmMuMRYwFAYDVQQLEw1WcG4gVW5saW1pdGVkMSMwIQYDVQQDExpzZXJ2ZXIudnBudW5saW1pdGVkYXBwLmNvbTEjMCEGA1UEKRMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xLjAsBgkqhkiG9w0BCQEWH3N1cHBvcnRAc2ltcGxleHNvbHV0aW9uc2luYy5jb20wHhcNMTMxMjE2MTM1OTQ0WhcNMjMxMjE0MTM1OTQ0WjCB4DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk5ZMREwDwYDVQQHEwhOZXcgWW9yazEfMB0GA1UEChMWU2ltcGxleCBTb2x1dGlvbnMgSW5jLjEWMBQGA1UECxMNVnBuIFVubGltaXRlZDEjMCEGA1UEAxMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xIzAhBgNVBCkTGnNlcnZlci52cG51bmxpbWl0ZWRhcHAuY29tMS4wLAYJKoZIhvcNAQkBFh9zdXBwb3J0QHNpbXBsZXhzb2x1dGlvbnNpbmMuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDADUzS8QWGvdhLFKsEzAiq5+b0ukKjBza0k6/dmCeYTvCVqGKg/h1IAtQdVVLAkmEp0zvGH7PuOhXm7zZrCouBr/RiG4tEcoRHwc6AJmowkYERlY7+xGx3OuNrD00QceNTsan0bn78jwt0zhFNmHdoTtFjgK3oqmQYSAtbEVWYgwIDAQABo4IBTDCCAUgwHQYDVR0OBBYEFKClmYP+tMNgWagUJCCHjtaui2k+MIIBFwYDVR0jBIIBDjCCAQqAFKClmYP+tMNgWagUJCCHjtaui2k+oYHmpIHjMIHgMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTlkxETAPBgNVBAcTCE5ldyBZb3JrMR8wHQYDVQQKExZTaW1wbGV4IFNvbHV0aW9ucyBJbmMuMRYwFAYDVQQLEw1WcG4gVW5saW1pdGVkMSMwIQYDVQQDExpzZXJ2ZXIudnBudW5saW1pdGVkYXBwLmNvbTEjMCEGA1UEKRMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xLjAsBgkqhkiG9w0BCQEWH3N1cHBvcnRAc2ltcGxleHNvbHV0aW9uc2luYy5jb22CCQCrFWxwXWpF7jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBALkWhfw7SSV7it+ZYZmT+cQbExjlYgQ40zae2J2CqIYACRcfsDHvh7Q+fiwSocevv2NE0dWi6WB2H6SiudYjvDvubAX/QbzfBxtbxCCoAIlfPCm8xOnWFN7TUJAzWwHJkKgEnu29GZHu2x8J+7VeDbKH5RTMHHe8FkSxh6Zz/BMN"
|
||||
)
|
||||
|
||||
func VPNUnlimitedCountryChoices() (choices []string) {
|
||||
servers := VPNUnlimitedServers()
|
||||
func VPNUnlimitedCountryChoices(servers []models.VPNUnlimitedServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -18,8 +17,7 @@ func VPNUnlimitedCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func VPNUnlimitedCityChoices() (choices []string) {
|
||||
servers := VPNUnlimitedServers()
|
||||
func VPNUnlimitedCityChoices(servers []models.VPNUnlimitedServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -27,18 +25,10 @@ func VPNUnlimitedCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func VPNUnlimitedHostnameChoices() (choices []string) {
|
||||
servers := VPNUnlimitedServers()
|
||||
func VPNUnlimitedHostnameChoices(servers []models.VPNUnlimitedServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// VPNUnlimitedServers returns a slice of all the server information for VPNUnlimited.
|
||||
func VPNUnlimitedServers() (servers []models.VPNUnlimitedServer) {
|
||||
servers = make([]models.VPNUnlimitedServer, len(allServers.VPNUnlimited.Servers))
|
||||
copy(servers, allServers.VPNUnlimited.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -9,18 +9,10 @@ const (
|
||||
VyprvpnCertificate = "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"
|
||||
)
|
||||
|
||||
func VyprvpnRegionChoices() (choices []string) {
|
||||
servers := VyprvpnServers()
|
||||
func VyprvpnRegionChoices(servers []models.VyprvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// VyprvpnServers returns a slice of all the VyprVPN servers.
|
||||
func VyprvpnServers() (servers []models.VyprvpnServer) {
|
||||
servers = make([]models.VyprvpnServer, len(allServers.Vyprvpn.Servers))
|
||||
copy(servers, allServers.Vyprvpn.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
26
internal/constants/wevpn.go
Normal file
26
internal/constants/wevpn.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package constants
|
||||
|
||||
import "github.com/qdm12/gluetun/internal/models"
|
||||
|
||||
//nolint:lll
|
||||
const (
|
||||
WevpnCA = "MIIDQjCCAiqgAwIBAgIUPppqnRZfvGGrT4GjXFE4Q29QzgowDQYJKoZIhvcNAQELBQAwEzERMA8GA1UEAwwIQ2hhbmdlTWUwHhcNMTkxMTA1MjMzMzIzWhcNMjkxMTAyMjMzMzIzWjATMREwDwYDVQQDDAhDaGFuZ2VNZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL5DFBJlTqhXukJFWlI8TNW9+HEQCZXhyVFvQhJFF2xIGVNx51XzqxiRANjVJZJrA68kV8az0v2Dxj0SFnRWDR6pOjjdp2CyHFcgHyfv+4MrsreAtkue86bB/1ECPWaoIwtaLnwI6SEmFZl98RlI9v4M/8IE4chOnMrM/F22+2OXI//TduvTcbyOMUiiouIP8UG1FB3J5FyuaW6qPZz2G0efDoaOI+E9LSxE87OoFrII7UqdHlWxRb3nUuPU1Ee4rN/d4tFyP4AvPKfsGhVOwyGG21IdRnbXIuDi0xytkCGOZ4j2bq5zqudnp4Izt6yJgdzZpQQWK3kSHB3qTT/Yzl8CAwEAAaOBjTCBijAdBgNVHQ4EFgQUXYkoo4WbkkvbgLVdGob9RScRf3AwTgYDVR0jBEcwRYAUXYkoo4WbkkvbgLVdGob9RScRf3ChF6QVMBMxETAPBgNVBAMMCENoYW5nZU1lghQ+mmqdFl+8YatPgaNcUThDb1DOCjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAOr1XmyWBRYfTQPNvZZ+DjCfiRYzLOi2AGefZt/jETqPDF8deVbyL1fLhXZzuX+5Etlsil3PflJjpzc/FSeZRuYRaShtwF3j6I08Eww9rBkaCnsukMUcLtMOvhdAU8dUakcRA2wkQ7Z+TWdMBv5+/6MnX10An1fIz7bAy3btMEOPTEFLo8Bst1SxJtUMaqhUteSOJ1VorpK3CWfOFaXxbJAb4E0+3zt6Vsc8mY5tt6wAi8IqiN4WD79ZdvKxENK4FMkR1kNpBY97mvdf82rzpwiBuJgN5ywmH78Ghj+9T8nI6/UIqJ1y22IRYGv6dMif8fHo5WWhCv3qmCqqY8vwuxw=="
|
||||
WevpnCertificate = "MIIDTDCCAjSgAwIBAgIRAKxt8SMIXezjmHm2KDCAQdIwDQYJKoZIhvcNAQELBQAwEzERMA8GA1UEAwwIQ2hhbmdlTWUwHhcNMTkxMTA1MjMzMzI0WhcNMjkxMTAyMjMzMzI0WjAOMQwwCgYDVQQDDAN0Y3AwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvEwY2erLhMm3Mpsnybm3G6zvGyeblUAaehQVEUs+KM2/5np0Ovx0y8Iz9pIC9ITaWM0B3dM6uBsNEtylZIe4Dd9aFujunSeCFsLRf8i9AbrUombpQ6P4jzYFBxwcEw//UShwa4HZI6JuSYikdpx/dyXdBH2skahwDVc8VUFdBLLSglfKGbuzP9GsdSwQCeBRWgA3dvIzIkQkBwfnt9WQKUfRAe8e5NybaAn8Yuu9sjLkQe6eyV7toxkZTcEXdABG2vtdTEzlAsQilZzIxg3jcdeEgMgRKngng+YNP0rR5nofZ1iDlp+vBj0nuqTTJLHMrRWPIc7bdYFD/f2J49WORAgMBAAGjgZ8wgZwwCQYDVR0TBAIwADAdBgNVHQ4EFgQUmSAFmCo1FAKVq8RQF7jMxMxcMtUwTgYDVR0jBEcwRYAUXYkoo4WbkkvbgLVdGob9RScRf3ChF6QVMBMxETAPBgNVBAMMCENoYW5nZU1lghQ+mmqdFl+8YatPgaNcUThDb1DOCjATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQELBQADggEBADPqdEgL+0kou8P974QEaNg1XOAXpwP0NNqbkZ/Oj9+Lp96YAhAHOAJig+RWbBktK8zu8oUUGR1qLXAWCmirlXErVuBRnadTEh3A7SOuY02BcsYAtpQ2EU9j5K/LV7nTfagkVdWy7x/av361UD4t9fv1j4YYTh4XLRp7KVXs6AGZ7T1hqPYFMUIoPpFhPzFxH4euJjfazr4SkTR6k6Vhw3pyFd6HP65vcqpzHGxFytSa8HtltBk2DpzIf8yV9TEy+gOXFaaGss0YKQ5OU1ieqZRuLVEGiu17lByYiQGyemIETJbdkyiSg93dDJRxjaTk7c8CEdpipt07ndSIPldMtXA="
|
||||
WevpnOpenvpnStaticKeyV1 = "7be66c0df0b8855e076d9e37b19f9ff3c1735ed537dee6dc786e51bdb8502f878077eeba0420a25e2b04814d22bbdcc0191a4fc396fdba1af6eb090a9d8664f18e70012ee98a2e32c28620a771d13cf3a619c417480c2c312562fffaebfd7ba73f57a28edde6c287365e6ce28291a29728da211cb53e01aa46b92f5f276c61fb46bd810b41219022c8f3d9e699fe9ade6bfcbb937fbbf6f49d741740e71c7c008a9a13c2432608038c6310b4f33588d8d234b3dffcf0823395267d73140d0e9a40e323ca92866c37073bfb072ab9de518bb9f2c65df7e219c2f114afbcf7c6e3c401cb08c3ed2901725b0601d2b5de89245719dd32506d52f149d14156215c1e"
|
||||
)
|
||||
|
||||
func WevpnCityChoices(servers []models.WevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func WevpnHostnameChoices(servers []models.WevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
import "github.com/qdm12/gluetun/internal/models"
|
||||
|
||||
//nolint:lll
|
||||
const (
|
||||
@@ -10,8 +8,7 @@ const (
|
||||
WindscribeOpenvpnStaticKeyV1 = "5801926a57ac2ce27e3dfd1dd6ef82042d82bd4f3f0021296f57734f6f1ea714a6623845541c4b0c3dea0a050fe6746cb66dfab14cda27e5ae09d7c155aa554f399fa4a863f0e8c1af787e5c602a801d3a2ec41e395a978d56729457fe6102d7d9e9119aa83643210b33c678f9d4109e3154ac9c759e490cb309b319cf708cae83ddadc3060a7a26564d1a24411cd552fe6620ea16b755697a4fc5e6e9d0cfc0c5c4a1874685429046a424c026db672e4c2c492898052ba59128d46200b40f880027a8b6610a4d559bdc9346d33a0a6b08e75c7fd43192b162bfd0aef0c716b31584827693f676f9a5047123466f0654eade34972586b31c6ce7e395f4b478cb"
|
||||
)
|
||||
|
||||
func WindscribeRegionChoices() (choices []string) {
|
||||
servers := WindscribeServers()
|
||||
func WindscribeRegionChoices(servers []models.WindscribeServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -19,8 +16,7 @@ func WindscribeRegionChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func WindscribeCityChoices() (choices []string) {
|
||||
servers := WindscribeServers()
|
||||
func WindscribeCityChoices(servers []models.WindscribeServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -28,18 +24,10 @@ func WindscribeCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func WindscribeHostnameChoices() (choices []string) {
|
||||
servers := WindscribeServers()
|
||||
func WindscribeHostnameChoices(servers []models.WindscribeServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// WindscribeServers returns a slice of all the Windscribe servers.
|
||||
func WindscribeServers() (servers []models.WindscribeServer) {
|
||||
servers = make([]models.WindscribeServer, len(allServers.Windscribe.Servers))
|
||||
copy(servers, allServers.Windscribe.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
8
internal/dns/logger.go
Normal file
8
internal/dns/logger.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package dns
|
||||
|
||||
type Logger interface {
|
||||
Debug(s string)
|
||||
Info(s string)
|
||||
Warn(s string)
|
||||
Error(s string)
|
||||
}
|
||||
@@ -6,7 +6,15 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
type logLevel uint8
|
||||
|
||||
const (
|
||||
levelDebug logLevel = iota
|
||||
levelInfo
|
||||
levelWarn
|
||||
levelError
|
||||
)
|
||||
|
||||
func (l *Loop) collectLines(ctx context.Context, done chan<- struct{},
|
||||
@@ -29,13 +37,13 @@ func (l *Loop) collectLines(ctx context.Context, done chan<- struct{},
|
||||
|
||||
line, level := processLogLine(line)
|
||||
switch level {
|
||||
case logging.LevelDebug:
|
||||
case levelDebug:
|
||||
l.logger.Debug(line)
|
||||
case logging.LevelInfo:
|
||||
case levelInfo:
|
||||
l.logger.Info(line)
|
||||
case logging.LevelWarn:
|
||||
case levelWarn:
|
||||
l.logger.Warn(line)
|
||||
case logging.LevelError:
|
||||
case levelError:
|
||||
l.logger.Error(line)
|
||||
}
|
||||
}
|
||||
@@ -43,24 +51,24 @@ func (l *Loop) collectLines(ctx context.Context, done chan<- struct{},
|
||||
|
||||
var unboundPrefix = regexp.MustCompile(`\[[0-9]{10}\] unbound\[[0-9]+:[0|1]\] `)
|
||||
|
||||
func processLogLine(s string) (filtered string, level logging.Level) {
|
||||
func processLogLine(s string) (filtered string, level logLevel) {
|
||||
prefix := unboundPrefix.FindString(s)
|
||||
filtered = s[len(prefix):]
|
||||
switch {
|
||||
case strings.HasPrefix(filtered, "notice: "):
|
||||
filtered = strings.TrimPrefix(filtered, "notice: ")
|
||||
level = logging.LevelInfo
|
||||
level = levelInfo
|
||||
case strings.HasPrefix(filtered, "info: "):
|
||||
filtered = strings.TrimPrefix(filtered, "info: ")
|
||||
level = logging.LevelInfo
|
||||
level = levelInfo
|
||||
case strings.HasPrefix(filtered, "warn: "):
|
||||
filtered = strings.TrimPrefix(filtered, "warn: ")
|
||||
level = logging.LevelWarn
|
||||
level = levelWarn
|
||||
case strings.HasPrefix(filtered, "error: "):
|
||||
filtered = strings.TrimPrefix(filtered, "error: ")
|
||||
level = logging.LevelError
|
||||
level = levelError
|
||||
default:
|
||||
level = logging.LevelInfo
|
||||
level = levelInfo
|
||||
}
|
||||
filtered = constants.ColorUnbound().Sprintf(filtered)
|
||||
return filtered, level
|
||||
|
||||
@@ -3,7 +3,6 @@ package dns
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -12,30 +11,30 @@ func Test_processLogLine(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
s string
|
||||
filtered string
|
||||
level logging.Level
|
||||
level logLevel
|
||||
}{
|
||||
"empty string": {"", "", logging.LevelInfo},
|
||||
"random string": {"asdasqdb", "asdasqdb", logging.LevelInfo},
|
||||
"empty string": {"", "", levelInfo},
|
||||
"random string": {"asdasqdb", "asdasqdb", levelInfo},
|
||||
"unbound notice": {
|
||||
"[1594595249] unbound[75:0] notice: init module 0: validator",
|
||||
"init module 0: validator",
|
||||
logging.LevelInfo},
|
||||
levelInfo},
|
||||
"unbound info": {
|
||||
"[1594595249] unbound[75:0] info: init module 0: validator",
|
||||
"init module 0: validator",
|
||||
logging.LevelInfo},
|
||||
levelInfo},
|
||||
"unbound warn": {
|
||||
"[1594595249] unbound[75:0] warn: init module 0: validator",
|
||||
"init module 0: validator",
|
||||
logging.LevelWarn},
|
||||
levelWarn},
|
||||
"unbound error": {
|
||||
"[1594595249] unbound[75:0] error: init module 0: validator",
|
||||
"init module 0: validator",
|
||||
logging.LevelError},
|
||||
levelError},
|
||||
"unbound unknown": {
|
||||
"[1594595249] unbound[75:0] BLA: init module 0: validator",
|
||||
"BLA: init module 0: validator",
|
||||
logging.LevelInfo},
|
||||
levelInfo},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
tc := tc
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/qdm12/gluetun/internal/dns/state"
|
||||
"github.com/qdm12/gluetun/internal/loopstate"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
var _ Looper = (*Loop)(nil)
|
||||
@@ -33,7 +32,7 @@ type Loop struct {
|
||||
resolvConf string
|
||||
blockBuilder blacklist.Builder
|
||||
client *http.Client
|
||||
logger logging.Logger
|
||||
logger Logger
|
||||
userTrigger bool
|
||||
start <-chan struct{}
|
||||
running chan<- models.LoopStatus
|
||||
@@ -48,7 +47,7 @@ type Loop struct {
|
||||
const defaultBackoffTime = 10 * time.Second
|
||||
|
||||
func NewLoop(conf unbound.Configurator, settings configuration.DNS, client *http.Client,
|
||||
logger logging.Logger) *Loop {
|
||||
logger Logger) *Loop {
|
||||
start := make(chan struct{})
|
||||
running := make(chan models.LoopStatus)
|
||||
stop := make(chan struct{})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user