oauth-tool 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9886d33c495d6518949769d978c9473d7d7daeb2967064628011677934c6f048
4
+ data.tar.gz: a4583d59e5ee705f2a3ada3c3d1401cf35f3c253d4d14f8e72bbdcd5bae1f086
5
+ SHA512:
6
+ metadata.gz: 7e494e7eed47442de0d76acd43d89a54ad08f8696843b0e6fbe767bdcff5eb4f345b76c1ac1580e1a6c3bde2224c4b4d5a7de6e2d4d64f44f4bf73e34dafea82
7
+ data.tar.gz: 4718488f6debce1e33df8593c857af29a90fe6278d6798173fd562076bff0714b73af181eabd9c6b20c9d025a980c6b791a52ac0b198aad6ff6d94e0f5eb064f
data/bin/oauth-tool ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/oauth_tool"
data/lib/oauth_tool.rb ADDED
@@ -0,0 +1,295 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "net/http"
4
+ require "uri"
5
+ require "json"
6
+ require "fileutils"
7
+
8
+ BASE = "https://probable-octo-winner.fly.dev"
9
+ TOKEN_FILE = File.join(Dir.home, ".oauth_access_token")
10
+ VERSION = "1.0.0"
11
+
12
+ def request(method, path, body = nil, token = nil)
13
+ uri = URI("#{BASE}#{path}")
14
+
15
+ http = Net::HTTP.new(uri.host, uri.port)
16
+ http.use_ssl = true
17
+
18
+ klass = {
19
+ "GET" => Net::HTTP::Get,
20
+ "POST" => Net::HTTP::Post
21
+ }[method]
22
+
23
+ raise "Unsupported HTTP method: #{method}" unless klass
24
+
25
+ req = klass.new(uri)
26
+ req["Content-Type"] = "application/json"
27
+ req["Authorization"] = "Bearer #{token}" if token
28
+ req.body = JSON.generate(body) if body
29
+
30
+ response = http.request(req)
31
+
32
+ begin
33
+ JSON.parse(response.body)
34
+ rescue JSON::ParserError
35
+ {
36
+ "raw" => response.body,
37
+ "status" => response.code.to_i
38
+ }
39
+ end
40
+ end
41
+
42
+ def save_token(token)
43
+ File.write(TOKEN_FILE, "#{token}\n")
44
+ File.chmod(0600, TOKEN_FILE)
45
+ end
46
+
47
+ def load_token
48
+ return nil unless File.file?(TOKEN_FILE)
49
+
50
+ token = File.read(TOKEN_FILE).strip
51
+ token.empty? ? nil : token
52
+ end
53
+
54
+ def help
55
+ puts <<~HELP
56
+ OAuth Tool #{VERSION}
57
+
58
+ Usage:
59
+ oauth-tool [command] [options]
60
+
61
+ Commands:
62
+ help Show this help
63
+ health Check API health
64
+ auth register Create an account
65
+ auth login Start OAuth device login
66
+ auth status Check authentication
67
+ auth logout Remove saved token
68
+ auth help Show authentication help
69
+ get Get protected RAM information
70
+
71
+ Options:
72
+ -h, --help Show help
73
+ -v, --version Show version
74
+ HELP
75
+ end
76
+
77
+ def auth_help
78
+ puts <<~HELP
79
+ OAuth authentication commands:
80
+
81
+ oauth-tool auth register
82
+ oauth-tool auth login
83
+ oauth-tool auth status
84
+ oauth-tool auth logout
85
+ oauth-tool auth help
86
+ HELP
87
+ end
88
+
89
+ def register
90
+ print "Username: "
91
+ username = STDIN.gets&.strip
92
+
93
+ if username.nil? || username.empty?
94
+ puts "Username is required."
95
+ return
96
+ end
97
+
98
+ print "Password: "
99
+
100
+ if STDIN.tty?
101
+ system("stty -echo")
102
+ end
103
+
104
+ password = STDIN.gets&.strip
105
+
106
+ if STDIN.tty?
107
+ system("stty echo")
108
+ end
109
+
110
+ puts
111
+
112
+ if password.nil? || password.empty?
113
+ puts "Password is required."
114
+ return
115
+ end
116
+
117
+ result = request(
118
+ "POST",
119
+ "/api/auth/register",
120
+ {
121
+ username: username,
122
+ password: password
123
+ }
124
+ )
125
+
126
+ puts JSON.pretty_generate(result)
127
+ end
128
+
129
+ def login
130
+ puts "Generating OAuth device code..."
131
+
132
+ data = request("POST", "/oauth/device/code", {})
133
+
134
+ unless data["device_code"]
135
+ puts JSON.pretty_generate(data)
136
+ return
137
+ end
138
+
139
+ device_code = data["device_code"]
140
+ user_code = data["user_code"]
141
+ verify_url =
142
+ data["verification_uri_complete"] ||
143
+ data["verification_uri"]
144
+
145
+ interval = (data["interval"] || 5).to_i
146
+
147
+ puts
148
+ puts "======================================"
149
+ puts " OAuth Device Authorization"
150
+ puts "======================================"
151
+ puts
152
+ puts "User code: #{user_code}"
153
+ puts
154
+ puts "Verification URL: #{verify_url}"
155
+ puts
156
+ puts "Open the URL and authorize the device."
157
+ puts "Waiting for authorization..."
158
+
159
+ loop do
160
+ token_data = request(
161
+ "POST",
162
+ "/oauth2/token",
163
+ { device_code: device_code }
164
+ )
165
+
166
+ if token_data["access_token"]
167
+ save_token(token_data["access_token"])
168
+
169
+ puts
170
+ puts "Authorization completed."
171
+ puts "Access token saved:"
172
+ puts TOKEN_FILE
173
+ return
174
+ end
175
+
176
+ if token_data["error"] == "authorization_pending"
177
+ print "."
178
+ sleep interval
179
+ next
180
+ end
181
+
182
+ puts
183
+ puts "OAuth token request failed:"
184
+ puts JSON.pretty_generate(token_data)
185
+ return
186
+ end
187
+ end
188
+
189
+ def status
190
+ token = load_token
191
+
192
+ unless token
193
+ puts '{"authenticated":false}'
194
+ return
195
+ end
196
+
197
+ result = request(
198
+ "GET",
199
+ "/api/oauth/status",
200
+ nil,
201
+ token
202
+ )
203
+
204
+ puts JSON.pretty_generate(result)
205
+ end
206
+
207
+ def logout
208
+ token = load_token
209
+
210
+ unless token
211
+ puts "Not authenticated."
212
+ return
213
+ end
214
+
215
+ result = request(
216
+ "POST",
217
+ "/api/auth/logout",
218
+ {},
219
+ token
220
+ )
221
+
222
+ File.delete(TOKEN_FILE) if File.exist?(TOKEN_FILE)
223
+
224
+ puts JSON.pretty_generate(result)
225
+ puts "Local access token removed."
226
+ end
227
+
228
+ def get_ram
229
+ token = load_token
230
+
231
+ unless token
232
+ puts "Not authenticated."
233
+ puts "Run: oauth-tool auth login"
234
+ return
235
+ end
236
+
237
+ result = request(
238
+ "GET",
239
+ "/api/get-ram",
240
+ nil,
241
+ token
242
+ )
243
+
244
+ puts JSON.pretty_generate(result)
245
+ end
246
+
247
+ args = ARGV.dup
248
+
249
+ if args.empty? ||
250
+ args[0] == "help" ||
251
+ args[0] == "-h" ||
252
+ args[0] == "--help"
253
+
254
+ help
255
+ exit
256
+ end
257
+
258
+ if args[0] == "-v" || args[0] == "--version"
259
+ puts VERSION
260
+ exit
261
+ end
262
+
263
+ case args[0]
264
+ when "health"
265
+ puts JSON.pretty_generate(
266
+ request("GET", "/api/health")
267
+ )
268
+
269
+ when "get"
270
+ get_ram
271
+
272
+ when "auth"
273
+ case args[1]
274
+ when "register"
275
+ register
276
+ when "login"
277
+ login
278
+ when "status"
279
+ status
280
+ when "logout"
281
+ logout
282
+ when "help", nil
283
+ auth_help
284
+ else
285
+ warn "Unknown auth command: #{args[1]}"
286
+ auth_help
287
+ exit 1
288
+ end
289
+
290
+ else
291
+ warn "Unknown command: #{args[0]}"
292
+ puts
293
+ help
294
+ exit 1
295
+ end
@@ -0,0 +1,21 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "oauth-tool"
3
+ spec.version = "1.0.0"
4
+ spec.authors = ["Jjjm"]
5
+ spec.summary = "OAuth device authorization CLI"
6
+ spec.description = "CLI for OAuth device authentication and protected API access."
7
+ spec.homepage = "https://probable-octo-winner.fly.dev"
8
+ spec.license = "MIT"
9
+
10
+ spec.required_ruby_version = ">= 3.0"
11
+
12
+ spec.files = [
13
+ "bin/oauth-tool",
14
+ "lib/oauth_tool.rb",
15
+ "oauth-tool.gemspec"
16
+ ]
17
+
18
+ spec.bindir = "bin"
19
+ spec.executables = ["oauth-tool"]
20
+ spec.require_paths = ["lib"]
21
+ end
metadata ADDED
@@ -0,0 +1,42 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oauth-tool
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jjjm
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2026-08-13 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: CLI for OAuth device authentication and protected API access.
13
+ executables:
14
+ - oauth-tool
15
+ extensions: []
16
+ extra_rdoc_files: []
17
+ files:
18
+ - bin/oauth-tool
19
+ - lib/oauth_tool.rb
20
+ - oauth-tool.gemspec
21
+ homepage: https://probable-octo-winner.fly.dev
22
+ licenses:
23
+ - MIT
24
+ metadata: {}
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ required_rubygems_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ requirements: []
39
+ rubygems_version: 3.6.2
40
+ specification_version: 4
41
+ summary: OAuth device authorization CLI
42
+ test_files: []