vpn-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/bin/vpn-sdk +235 -0
  3. data/lib/vpn_sdk.rb +81 -0
  4. metadata +43 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 53f60eddcb559c61baf0a67f2b7011a52d720bf8cb708bd8a342790db892011e
4
+ data.tar.gz: c62f2751492090d7a3e791c94b82724e09ee2986efef21b9f19ea6dc3bdcf475
5
+ SHA512:
6
+ metadata.gz: b602b55b4ab8f28799a3fe3cfb54b2d8fb515cbb9fc15d1856050623639ccc3e9e630685be231eedf2f19302adeb93218699692f988f081c11bc3bc666b8e5e9
7
+ data.tar.gz: a1b4223a76959b160ef285f3df78e3ad2e38525ec96864349170a1af6e3f1d37bd3324d1a855a44830561ca30d79dc6e42d50ea7f9216719d56288c0cc292fb1
data/bin/vpn-sdk ADDED
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'io/console'
4
+ require 'json'
5
+ require 'digest'
6
+ require_relative '../lib/vpn_sdk'
7
+
8
+ class AuthManager
9
+ AUTH_FILE = File.join(Dir.home, '.vpn_sdk_auth.json')
10
+ MAX_ATTEMPTS = 3
11
+ LOCKOUT_TIME = 30
12
+
13
+ def self.load_data
14
+ return { 'pin_hash' => nil, 'attempts' => 0, 'lockout_until' => 0, 'session_active' => false } unless File.exist?(AUTH_FILE)
15
+
16
+ JSON.parse(File.read(AUTH_FILE))
17
+ rescue StandardError
18
+ { 'pin_hash' => nil, 'attempts' => 0, 'lockout_until' => 0, 'session_active' => false }
19
+ end
20
+
21
+ def self.save_data(data)
22
+ File.write(AUTH_FILE, JSON.pretty_generate(data))
23
+ end
24
+
25
+ def self.hash_pin(pin)
26
+ Digest::SHA256.hexdigest(pin)
27
+ end
28
+
29
+ def self.check_lockout!
30
+ data = load_data
31
+ now = Time.now.to_i
32
+
33
+ if data['lockout_until'] > now
34
+ remaining = data['lockout_until'] - now
35
+ puts "\nāŒ Access Denied: Too many failed PIN attempts."
36
+ puts "šŸ”’ System locked. Please wait #{remaining} seconds before trying again."
37
+ exit(1)
38
+ end
39
+ end
40
+
41
+ def self.authenticated?
42
+ data = load_data
43
+ data['session_active'] == true
44
+ end
45
+
46
+ def self.register_pin(pin)
47
+ data = load_data
48
+ data['pin_hash'] = hash_pin(pin)
49
+ data['attempts'] = 0
50
+ data['lockout_until'] = 0
51
+ data['session_active'] = true
52
+ save_data(data)
53
+ end
54
+
55
+ def self.verify_pin(pin)
56
+ check_lockout!
57
+ data = load_data
58
+
59
+ if data['pin_hash'].nil?
60
+ puts "\nāŒ Access Denied: No PIN registered. Run 'auth register' first."
61
+ exit(1)
62
+ end
63
+
64
+ if hash_pin(pin) == data['pin_hash']
65
+ data['attempts'] = 0
66
+ data['session_active'] = true
67
+ save_data(data)
68
+ true
69
+ else
70
+ data['attempts'] += 1
71
+ if data['attempts'] >= MAX_ATTEMPTS
72
+ data['lockout_until'] = Time.now.to_i + LOCKOUT_TIME
73
+ data['attempts'] = 0
74
+ data['session_active'] = false
75
+ save_data(data)
76
+ puts "\nāŒ Access Denied: Incorrect PIN."
77
+ puts "šŸ”’ Account locked due to #{MAX_ATTEMPTS} failed attempts. Try again in #{LOCKOUT_TIME}s."
78
+ else
79
+ remaining_attempts = MAX_ATTEMPTS - data['attempts']
80
+ save_data(data)
81
+ puts "\nāŒ Access Denied: Incorrect PIN. Attempts remaining: #{remaining_attempts}"
82
+ end
83
+ false
84
+ end
85
+ end
86
+
87
+ def self.logout
88
+ data = load_data
89
+ data['session_active'] = false
90
+ save_data(data)
91
+ end
92
+ end
93
+
94
+ client = VpnSdk::Client.new
95
+
96
+ def ask_password(prompt)
97
+ print prompt
98
+ $stdin.noecho(&:gets).chomp.tap { puts }
99
+ end
100
+
101
+ def ask_question(prompt)
102
+ print prompt
103
+ $stdin.gets.chomp
104
+ end
105
+
106
+ def require_authentication!
107
+ AuthManager.check_lockout!
108
+ unless AuthManager.authenticated?
109
+ puts "\nāŒ Access Denied: PIN session expired or locked."
110
+ puts "Please authenticate using 'auth login' first."
111
+ exit(1)
112
+ end
113
+ end
114
+
115
+ command = ARGV[0]
116
+ subcommand = ARGV[1]
117
+ option = ARGV[2]
118
+
119
+ case command
120
+ when 'health'
121
+ require_authentication!
122
+ res = client.check_health
123
+ puts "\nHealth Check Response:"
124
+ puts JSON.pretty_generate(res)
125
+
126
+ when 'countries'
127
+ require_authentication!
128
+ countries = client.countries
129
+ puts "\nSupported Countries:"
130
+ puts '-' * 50
131
+ if countries.is_a?(Array)
132
+ countries.each do |c|
133
+ flag = c['flag'] || '🌐'
134
+ name = c['name'] || c['code']
135
+ puts "#{flag} #{name} (#{c['code']}) - #{c['serverCount']} Servers [#{c['latency']}ms]"
136
+ end
137
+ else
138
+ puts JSON.pretty_generate(countries)
139
+ end
140
+
141
+ when 'servers'
142
+ require_authentication!
143
+ country_code = option || ARGV[3]
144
+ if country_code.nil? || country_code.empty?
145
+ country_code = ask_question('Enter country code (optional, press Enter for all): ')
146
+ end
147
+ res = client.servers(country_code.strip)
148
+ puts "\nServers Response:"
149
+ puts JSON.pretty_generate(res)
150
+
151
+ when 'status'
152
+ require_authentication!
153
+ res = client.status
154
+ puts "\nVPN Status:"
155
+ puts JSON.pretty_generate(res)
156
+
157
+ when 'create'
158
+ require_authentication!
159
+ country_code = option || ARGV[3]
160
+ res = client.create_session(country_code)
161
+ puts "\nCreate Session Result:"
162
+ puts JSON.pretty_generate(res)
163
+
164
+ when 'connect'
165
+ require_authentication!
166
+ country_code = option || ARGV[3]
167
+ if country_code.nil? || country_code.empty?
168
+ countries = client.countries
169
+ puts "\nSupported Countries:"
170
+ countries.each { |c| puts " - [#{c['code']}] #{c['flag']} #{c['name']}" } if countries.is_a?(Array)
171
+ country_code = ask_question("\nEnter country code to connect: ")
172
+ end
173
+ res = client.connect(country_code)
174
+ puts "\nConnecting to [#{country_code}] Response:"
175
+ puts JSON.pretty_generate(res)
176
+
177
+ when 'disconnect'
178
+ require_authentication!
179
+ res = client.disconnect
180
+ puts "\nDisconnect Response:"
181
+ puts JSON.pretty_generate(res)
182
+
183
+ when 'auth'
184
+ case subcommand
185
+ when 'status'
186
+ data = AuthManager.load_data
187
+ now = Time.now.to_i
188
+ puts "\nAuth Lock System Status:"
189
+ puts '-' * 25
190
+ if data['lockout_until'] > now
191
+ puts "Status: šŸ”’ LOCKED (Wait #{data['lockout_until'] - now}s)"
192
+ elsif AuthManager.authenticated?
193
+ puts "Status: āœ… Authenticated"
194
+ else
195
+ puts "Status: āŒ Unauthenticated / Locked"
196
+ end
197
+ puts "Failed Attempts: #{data['attempts']}/#{AuthManager::MAX_ATTEMPTS}"
198
+
199
+ when 'login'
200
+ pin = ask_password('Enter PIN: ')
201
+ if AuthManager.verify_pin(pin)
202
+ puts 'āœ… PIN authentication successful.'
203
+ end
204
+
205
+ when 'register'
206
+ new_pin = ask_password('Enter new PIN: ')
207
+ confirm_pin = ask_password('Confirm new PIN: ')
208
+ if !new_pin.empty? && new_pin == confirm_pin
209
+ AuthManager.register_pin(new_pin)
210
+ puts 'āœ… New PIN registered and session authenticated successfully.'
211
+ else
212
+ $stderr.puts 'āŒ Error: PINs do not match or are empty!'
213
+ end
214
+
215
+ when 'logout'
216
+ AuthManager.logout
217
+ puts 'āœ… Logged out successfully.'
218
+
219
+ else
220
+ puts "Unknown auth command. Available: status, login, register, logout"
221
+ end
222
+
223
+ else
224
+ puts "VPN Gateway CLI & SDK (Ruby)"
225
+ puts "Usage: vpn-sdk <command> [options]"
226
+ puts "\nCommands:"
227
+ puts " health"
228
+ puts " countries"
229
+ puts " servers"
230
+ puts " status"
231
+ puts " create"
232
+ puts " connect"
233
+ puts " disconnect"
234
+ puts " auth status | auth login | auth register | auth logout"
235
+ end
data/lib/vpn_sdk.rb ADDED
@@ -0,0 +1,81 @@
1
+ require 'net/http'
2
+ require 'json'
3
+ require 'uri'
4
+
5
+ module VpnSdk
6
+ class Client
7
+ BASE_URL = 'https://vpn-gateway-deploy--bxhxbb352.replit.app'.freeze
8
+
9
+ attr_accessor :base_url, :timeout
10
+
11
+ def initialize(base_url = BASE_URL, timeout: 10)
12
+ @base_url = base_url
13
+ @timeout = timeout
14
+ end
15
+
16
+ def check_health
17
+ get('/api/healthz')
18
+ end
19
+
20
+ def countries
21
+ get('/api/vpn/countries')
22
+ end
23
+
24
+ def servers(country_code = nil)
25
+ path = if country_code && !country_code.to_s.empty?
26
+ "/api/vpn/servers?countryCode=#{URI.encode_www_form_component(country_code)}"
27
+ else
28
+ '/api/vpn/servers'
29
+ end
30
+ get(path)
31
+ end
32
+
33
+ def status
34
+ get('/api/vpn/status')
35
+ end
36
+
37
+ def create_session(country_code = nil)
38
+ payload = country_code ? { countryCode: country_code } : {}
39
+ post('/api/vpn/create', payload)
40
+ end
41
+
42
+ def connect(country_code)
43
+ post('/api/vpn/connect', { countryCode: country_code })
44
+ end
45
+
46
+ def disconnect
47
+ post('/api/vpn/disconnect', {})
48
+ end
49
+
50
+ private
51
+
52
+ def get(path)
53
+ uri = URI.parse("#{@base_url}#{path}")
54
+ req = Net::HTTP::Get.new(uri)
55
+ req['Content-Type'] = 'application/json'
56
+ perform_request(uri, req)
57
+ end
58
+
59
+ def post(path, payload)
60
+ uri = URI.parse("#{@base_url}#{path}")
61
+ req = Net::HTTP::Post.new(uri)
62
+ req['Content-Type'] = 'application/json'
63
+ req.body = payload.to_json
64
+ perform_request(uri, req)
65
+ end
66
+
67
+ def perform_request(uri, request)
68
+ http = Net::HTTP.new(uri.host, uri.port)
69
+ http.use_ssl = (uri.scheme == 'https')
70
+ http.open_timeout = @timeout
71
+ http.read_timeout = @timeout
72
+
73
+ response = http.request(request)
74
+ JSON.parse(response.body)
75
+ rescue JSON::ParserError
76
+ { 'status' => response.code, 'body' => response.body }
77
+ rescue StandardError => e
78
+ { 'error' => e.message }
79
+ end
80
+ end
81
+ end
metadata ADDED
@@ -0,0 +1,43 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vpn-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Maintainer
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2026-08-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: A lightweight Ruby wrapper and CLI executable for the VPN Gateway backend
13
+ API with PIN authentication.
14
+ email:
15
+ - dodi66412@gmail.com
16
+ executables:
17
+ - vpn-sdk
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - bin/vpn-sdk
22
+ - lib/vpn_sdk.rb
23
+ licenses:
24
+ - MIT
25
+ metadata: {}
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.6.0
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ requirements: []
40
+ rubygems_version: 3.6.2
41
+ specification_version: 4
42
+ summary: Ruby SDK and CLI tool for VPN Gateway API
43
+ test_files: []