Skip to content

Commit 6e3554b

Browse files
hatemosphereclaude
andauthored
Update deps to Go 1.25.6, fix API code per official Proton sources (#5)
* Update deps to Go 1.25.6, fix API code per official Proton sources - Upgrade Go 1.25.6 and all dependencies to latest versions - Fix certificate feature keys to match python-proton-vpn-api-core - Fix token refresh RedirectURI to match proton-python-client - Add IsSuccessCode() helper for API codes 1000/1001 - Fix error codes per protoncore_android ResponseCodes.kt - Extract API documentation to API_REFERENCE.md * add forgotten new line * upd deps in ci * fix: align comment whitespace in client.go Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * rename to confgen --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent e8913ea commit 6e3554b

File tree

19 files changed

+307
-129
lines changed

19 files changed

+307
-129
lines changed

.github/workflows/ci.yml

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@ on:
77
branches: [main]
88

99
env:
10-
GO_VERSION: "1.25.5"
11-
GOLANGCI_LINT_VERSION: "v2.6.1"
10+
GO_VERSION: "1.25.6"
11+
GOLANGCI_LINT_VERSION: "v2.8.0"
1212

1313
jobs:
1414
lint:
1515
name: Lint
1616
runs-on: ubuntu-latest
1717
steps:
18-
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
18+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
1919

2020
- name: Set up Go
21-
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
21+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
2222
with:
2323
go-version: ${{ env.GO_VERSION }}
2424
cache: true
@@ -43,10 +43,10 @@ jobs:
4343
name: Test
4444
runs-on: ubuntu-latest
4545
steps:
46-
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
46+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
4747

4848
- name: Set up Go
49-
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
49+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
5050
with:
5151
go-version: ${{ env.GO_VERSION }}
5252
cache: true
@@ -62,16 +62,16 @@ jobs:
6262
matrix:
6363
os: [ubuntu-latest, macos-latest, windows-latest]
6464
steps:
65-
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
65+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
6666

6767
- name: Set up Go
68-
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
68+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
6969
with:
7070
go-version: ${{ env.GO_VERSION }}
7171
cache: true
7272

7373
- name: Build (native)
74-
run: go build -o build/protonvpn-wg-config-generate${{ matrix.os == 'windows-latest' && '.exe' || '' }} cmd/protonvpn-wg/main.go
74+
run: go build -o build/protonvpn-wg-confgen${{ matrix.os == 'windows-latest' && '.exe' || '' }} cmd/protonvpn-wg/main.go
7575

7676
cross-compile:
7777
name: Cross-compile
@@ -100,10 +100,10 @@ jobs:
100100
goarch: arm64
101101
ext: .exe
102102
steps:
103-
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
103+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
104104

105105
- name: Set up Go
106-
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
106+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
107107
with:
108108
go-version: ${{ env.GO_VERSION }}
109109
cache: true
@@ -115,10 +115,10 @@ jobs:
115115
CGO_ENABLED: "0"
116116
run: |
117117
mkdir -p build
118-
go build -o build/protonvpn-wg-config-generate-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.ext }} cmd/protonvpn-wg/main.go
118+
go build -o build/protonvpn-wg-confgen-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.ext }} cmd/protonvpn-wg/main.go
119119
120120
- name: Upload artifact
121-
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
121+
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
122122
with:
123-
name: protonvpn-wg-config-generate-${{ matrix.goos }}-${{ matrix.goarch }}
124-
path: build/protonvpn-wg-config-generate-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.ext }}
123+
name: protonvpn-wg-confgen-${{ matrix.goos }}-${{ matrix.goarch }}
124+
path: build/protonvpn-wg-confgen-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.ext }}

.github/workflows/release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@ permissions:
99
contents: write
1010

1111
env:
12-
GO_VERSION: "1.25.5"
12+
GO_VERSION: "1.25.6"
1313

1414
jobs:
1515
release:
1616
name: Release
1717
runs-on: ubuntu-latest
1818
steps:
1919
- name: Checkout
20-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
20+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2121
with:
2222
fetch-depth: 0
2323

2424
- name: Set up Go
25-
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
25+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
2626
with:
2727
go-version: ${{ env.GO_VERSION }}
2828
cache: true

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ vendor/
1818
build/
1919

2020
# Binary
21-
protonvpn-wg-config-generate
21+
protonvpn-wg-confgen
2222

2323
# IDE specific files
2424
.vscode/

.goreleaser.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
22
version: 2
33

4-
project_name: protonvpn-wg-config-generate
4+
project_name: protonvpn-wg-confgen
55

66
before:
77
hooks:
88
- go mod tidy
99

1010
builds:
11-
- id: protonvpn-wg-config-generate
11+
- id: protonvpn-wg-confgen
1212
main: ./cmd/protonvpn-wg
13-
binary: protonvpn-wg-config-generate
13+
binary: protonvpn-wg-confgen
1414
env:
1515
- CGO_ENABLED=0
1616
goos:
@@ -69,7 +69,7 @@ changelog:
6969
release:
7070
github:
7171
owner: '{{ envOrDefault "GITHUB_REPOSITORY_OWNER" "" }}'
72-
name: protonvpn-wg-config-generate
72+
name: protonvpn-wg-confgen
7373
draft: false
7474
prerelease: auto
7575
mode: replace

API_REFERENCE.md

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# API Reference Implementation
2+
3+
This project's API integration was developed by reverse-engineering ProtonVPN's authentication and VPN APIs. The implementation is based on patterns from these official Proton libraries:
4+
5+
## Authentication (SRP Protocol)
6+
- **[ProtonMail/proton-python-client](https://github.com/ProtonMail/proton-python-client)** - Python implementation of Proton's SRP authentication
7+
- Reference for: `/auth/info`, `/auth`, `/auth/2fa`, `/auth/refresh` endpoints
8+
- SRP protocol implementation patterns
9+
- **[ProtonMail/go-srp](https://github.com/ProtonMail/go-srp)** - Go SRP library (direct dependency)
10+
11+
## VPN API
12+
- **[ProtonVPN/python-proton-vpn-api-core](https://github.com/ProtonVPN/python-proton-vpn-api-core)** - Official Python VPN API client
13+
- Reference for: `/vpn/v1/certificate`, `/vpn/v1/logicals`, `/vpn/v1/sessions` endpoints
14+
- Server filtering and selection patterns
15+
- Certificate request format (`Duration`, `Features`)
16+
17+
## Key Generation
18+
- **[ProtonVPN/go-vpn-lib](https://github.com/ProtonVPN/go-vpn-lib)** - Ed25519 to X25519 key conversion (direct dependency)
19+
20+
## Client Version
21+
- **[ProtonVPN/proton-vpn-gtk-app](https://github.com/ProtonVPN/proton-vpn-gtk-app)** - Official Linux client
22+
- Source for `x-pm-appversion` header value (fetched dynamically at build time)
23+
24+
## API Endpoints Used
25+
26+
| Endpoint | Method | Description |
27+
|----------|--------|-------------|
28+
| `/core/v4/auth/info` | POST | Get SRP authentication parameters |
29+
| `/core/v4/auth` | POST | Authenticate with SRP proofs |
30+
| `/core/v4/auth/2fa` | POST | Submit 2FA code for session upgrade |
31+
| `/auth/refresh` | POST | Refresh session tokens |
32+
| `/vpn/v1/certificate` | POST | Generate WireGuard certificate |
33+
| `/vpn/v1/logicals` | GET | List available VPN servers |
34+
35+
## Certificate Request Format
36+
37+
The certificate request to `/vpn/v1/certificate` uses the following format:
38+
39+
```json
40+
{
41+
"ClientPublicKey": "<PEM-encoded public key>",
42+
"ClientPublicKeyMode": "EC",
43+
"Mode": "persistent",
44+
"DeviceName": "<device name>",
45+
"Duration": "<duration in minutes> min",
46+
"Features": {
47+
"NetShieldLevel": 0,
48+
"RandomNAT": false,
49+
"PortForwarding": false,
50+
"SplitTCP": true
51+
}
52+
}
53+
```
54+
55+
### Feature Keys
56+
57+
| Key | Type | Description |
58+
|-----|------|-------------|
59+
| `NetShieldLevel` | int | NetShield ad/malware blocking (0=off, 1=malware, 2=ads+malware) |
60+
| `RandomNAT` | bool | Moderate NAT / Random NAT for gaming |
61+
| `PortForwarding` | bool | Port forwarding support |
62+
| `SplitTCP` | bool | VPN Accelerator (performance optimization) |
63+
64+
## API Response Codes
65+
66+
**Official sources:**
67+
- [ProtonMail/protoncore_android - ResponseCodes.kt](https://github.com/ProtonMail/protoncore_android/blob/main/network/domain/src/main/kotlin/me/proton/core/network/domain/ResponseCodes.kt) - Kotlin constants (authoritative)
68+
- [ProtonMail/proton-python-client - README.md](https://github.com/ProtonMail/proton-python-client#error-handling) - Python client error handling
69+
- [ProtonMail/proton-python-client - api.py](https://github.com/ProtonMail/proton-python-client/blob/master/proton/api.py) - Python API implementation
70+
71+
### Success Codes
72+
| Code | Constant | Meaning |
73+
|------|----------|---------|
74+
| 1000 | OK | Success |
75+
| 1001 | - | Success (multi-status) |
76+
77+
### Authentication Errors
78+
| Code | Constant | Meaning |
79+
|------|----------|---------|
80+
| 8002 | PASSWORD_WRONG | Incorrect password |
81+
| 8100 | AUTH_SWITCH_TO_SSO | Switch to SSO authentication |
82+
| 8101 | AUTH_SWITCH_TO_SRP | Switch to SRP authentication |
83+
| 9001 | HUMAN_VERIFICATION_REQUIRED | CAPTCHA/human verification required |
84+
| 9002 | DEVICE_VERIFICATION_REQUIRED | Device verification required |
85+
| 9101 | SCOPE_REAUTH_LOCKED | Scope re-authentication locked |
86+
| 9102 | SCOPE_REAUTH_PASSWORD | Scope re-authentication requires password |
87+
88+
### Account Errors
89+
| Code | Constant | Meaning |
90+
|------|----------|---------|
91+
| 10001 | ACCOUNT_FAILED_GENERIC | Generic account failure |
92+
| 10002 | ACCOUNT_DELETED | Account has been deleted |
93+
| 10003 | ACCOUNT_DISABLED | Account has been disabled |
94+
95+
### Version Errors
96+
| Code | Constant | Meaning |
97+
|------|----------|---------|
98+
| 5003 | APP_VERSION_BAD | App version no longer supported |
99+
| 5005 | API_VERSION_INVALID | API version invalid |
100+
| 5099 | APP_VERSION_NOT_SUPPORTED_FOR_EXTERNAL_ACCOUNTS | App version not supported for external accounts |
101+
102+
### Other Errors
103+
| Code | Constant | Meaning |
104+
|------|----------|---------|
105+
| 6001 | BODY_PARSE_FAILURE | Request body parse failure |
106+
| 12081 | USER_CREATE_NAME_INVALID | Invalid username during creation |
107+
| 12087 | USER_CREATE_TOKEN_INVALID | Invalid token during user creation |
108+
109+
### VPN-Specific Codes (observed, not in official docs)
110+
| Code | Meaning | Notes |
111+
|------|---------|-------|
112+
| 9100 | 2FA required for VPN | VPN certificate endpoint requires 2FA-authenticated session |
113+
| 10013 | Mailbox password required | Legacy 2-password mode (proton-python-client says "RefreshToken invalid") |
114+
115+
**Note:** Codes 9100 and 10013 were observed during VPN operations but are not documented in the official protoncore_android library. Their meanings may vary by context.
116+
117+
## Required Headers
118+
119+
All authenticated requests require these headers:
120+
121+
```
122+
Authorization: Bearer <access_token>
123+
x-pm-uid: <session_uid>
124+
x-pm-appversion: linux-vpn@X.Y.Z
125+
User-Agent: ProtonVPN/X.Y.Z (Linux; Ubuntu)
126+
Content-Type: application/json
127+
```
128+
129+
**Important**: Using a web client version (like `web-vpn-settings@X.Y.Z`) may trigger CAPTCHA challenges. Always use the Linux client version format.
130+
131+
## Token Refresh
132+
133+
The token refresh endpoint expects:
134+
135+
```json
136+
{
137+
"ResponseType": "token",
138+
"GrantType": "refresh_token",
139+
"RefreshToken": "<refresh_token>",
140+
"RedirectURI": "http://protonmail.ch"
141+
}
142+
```
143+
144+
## Local Reference Libraries
145+
146+
For debugging and verification, reference implementations are cloned in `.debug-libs/`:
147+
- `proton-python-client` - SRP authentication reference
148+
- `python-proton-vpn-api-core` - VPN API reference
149+
- `proton-vpn-gtk-app` - Linux client reference

Makefile

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,42 @@
1-
.PHONY: build clean test fmt vet lint install vendor
1+
.PHONY: build build-all clean test fmt vet lint install vendor run dev show-version
22

3-
BINARY_NAME=protonvpn-wg-config-generate
3+
BINARY_NAME=protonvpn-wg-confgen
44
BUILD_DIR=build
55
CMD_DIR=cmd/protonvpn-wg
6+
MODULE=protonvpn-wg-confgen
7+
8+
# Fetch latest ProtonVPN Linux client version from GitHub (with fallback)
9+
PROTON_VERSION_URL=https://raw.githubusercontent.com/ProtonVPN/proton-vpn-gtk-app/stable/versions.yml
10+
PROTON_VERSION ?= $(shell curl -sf "$(PROTON_VERSION_URL)" 2>/dev/null | head -1 | cut -d' ' -f2 || echo "4.13.1")
11+
12+
# ldflags to inject version at build time
13+
LDFLAGS=-ldflags "-X '$(MODULE)/internal/constants.AppVersion=linux-vpn@$(PROTON_VERSION)' \
14+
-X '$(MODULE)/internal/constants.UserAgent=ProtonVPN/$(PROTON_VERSION) (Linux; Ubuntu)'"
615

716
# Build the binary
817
build:
9-
@echo "Building $(BINARY_NAME)..."
18+
@echo "Building $(BINARY_NAME) with ProtonVPN client version $(PROTON_VERSION)..."
1019
@mkdir -p $(BUILD_DIR)
11-
@go build -o $(BUILD_DIR)/$(BINARY_NAME) $(CMD_DIR)/main.go
20+
@go build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME) $(CMD_DIR)/main.go
1221

1322
# Build for multiple platforms
1423
build-all:
15-
@echo "Building for multiple platforms..."
24+
@echo "Building for multiple platforms with ProtonVPN client version $(PROTON_VERSION)..."
1625
@mkdir -p $(BUILD_DIR)
1726
@echo " Linux amd64..."
18-
@GOOS=linux GOARCH=amd64 go build -o $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64 $(CMD_DIR)/main.go
27+
@GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64 $(CMD_DIR)/main.go
1928
@echo " Linux arm64..."
20-
@GOOS=linux GOARCH=arm64 go build -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 $(CMD_DIR)/main.go
29+
@GOOS=linux GOARCH=arm64 go build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 $(CMD_DIR)/main.go
2130
@echo " Linux arm..."
22-
@GOOS=linux GOARCH=arm go build -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm $(CMD_DIR)/main.go
31+
@GOOS=linux GOARCH=arm go build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm $(CMD_DIR)/main.go
2332
@echo " macOS amd64..."
24-
@GOOS=darwin GOARCH=amd64 go build -o $(BUILD_DIR)/$(BINARY_NAME)-darwin-amd64 $(CMD_DIR)/main.go
33+
@GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-darwin-amd64 $(CMD_DIR)/main.go
2534
@echo " macOS arm64..."
26-
@GOOS=darwin GOARCH=arm64 go build -o $(BUILD_DIR)/$(BINARY_NAME)-darwin-arm64 $(CMD_DIR)/main.go
35+
@GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-darwin-arm64 $(CMD_DIR)/main.go
2736
@echo " Windows amd64..."
28-
@GOOS=windows GOARCH=amd64 go build -o $(BUILD_DIR)/$(BINARY_NAME)-windows-amd64.exe $(CMD_DIR)/main.go
37+
@GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-windows-amd64.exe $(CMD_DIR)/main.go
2938
@echo " Windows arm64..."
30-
@GOOS=windows GOARCH=arm64 go build -o $(BUILD_DIR)/$(BINARY_NAME)-windows-arm64.exe $(CMD_DIR)/main.go
39+
@GOOS=windows GOARCH=arm64 go build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-windows-arm64.exe $(CMD_DIR)/main.go
3140
@echo "Done!"
3241

3342
# Clean build artifacts
@@ -72,5 +81,9 @@ run: build
7281

7382
# Development build with race detector
7483
dev:
75-
@echo "Building with race detector..."
76-
@go build -race -o $(BUILD_DIR)/$(BINARY_NAME)-dev $(CMD_DIR)/main.go
84+
@echo "Building with race detector and ProtonVPN client version $(PROTON_VERSION)..."
85+
@go build -race $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-dev $(CMD_DIR)/main.go
86+
87+
# Show current ProtonVPN version that would be used
88+
show-version:
89+
@echo "ProtonVPN client version: $(PROTON_VERSION)"

0 commit comments

Comments
 (0)