authproto 0.3.0.beta1

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 (115) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +1 -0
  3. data/.rubocop.yml +31 -0
  4. data/.tm_properties +1 -0
  5. data/.yardopts +4 -0
  6. data/CHANGELOG.md +52 -0
  7. data/MIT-LICENSE.txt +21 -0
  8. data/README.md +304 -0
  9. data/Rakefile +8 -0
  10. data/SECURITY.md +16 -0
  11. data/examples/confidential_client/.gitignore +5 -0
  12. data/examples/confidential_client/Gemfile +14 -0
  13. data/examples/confidential_client/Gemfile.lock +88 -0
  14. data/examples/confidential_client/README.md +226 -0
  15. data/examples/confidential_client/app.rb +290 -0
  16. data/examples/confidential_client/config/client-metadata.example.json +25 -0
  17. data/examples/confidential_client/config.ru +4 -0
  18. data/examples/confidential_client/public/styles.css +70 -0
  19. data/examples/confidential_client/screenshots/screenshot-1-sign-in.png +0 -0
  20. data/examples/confidential_client/screenshots/screenshot-2-success.png +0 -0
  21. data/examples/confidential_client/scripts/generate_keys.rb +15 -0
  22. data/examples/confidential_client/views/authorized.erb +46 -0
  23. data/examples/confidential_client/views/index.erb +44 -0
  24. data/examples/confidential_client/views/layout.erb +11 -0
  25. data/examples/minisky_console/.gitignore +2 -0
  26. data/examples/minisky_console/Gemfile +12 -0
  27. data/examples/minisky_console/Gemfile.lock +131 -0
  28. data/examples/minisky_console/README.md +112 -0
  29. data/examples/minisky_console/app.rb +50 -0
  30. data/examples/minisky_console/bin/console +6 -0
  31. data/examples/minisky_console/config.ru +5 -0
  32. data/examples/minisky_console/localhost.rb +53 -0
  33. data/examples/minisky_console/production.rb +32 -0
  34. data/lib/authproto/client.rb +583 -0
  35. data/lib/authproto/client_metadata.rb +478 -0
  36. data/lib/authproto/configuration.rb +139 -0
  37. data/lib/authproto/dpop/client.rb +161 -0
  38. data/lib/authproto/dpop/key_manager.rb +223 -0
  39. data/lib/authproto/dpop/nonce_manager.rb +145 -0
  40. data/lib/authproto/dpop/proof_generator.rb +124 -0
  41. data/lib/authproto/dpop/stored_nonce.rb +37 -0
  42. data/lib/authproto/encryption.rb +250 -0
  43. data/lib/authproto/errors.rb +75 -0
  44. data/lib/authproto/http_client.rb +320 -0
  45. data/lib/authproto/insecure_http_client.rb +24 -0
  46. data/lib/authproto/localhost_server.rb +274 -0
  47. data/lib/authproto/minisky.rb +273 -0
  48. data/lib/authproto/par/client.rb +240 -0
  49. data/lib/authproto/par/client_assertion.rb +69 -0
  50. data/lib/authproto/par/request.rb +243 -0
  51. data/lib/authproto/par/response.rb +43 -0
  52. data/lib/authproto/par.rb +48 -0
  53. data/lib/authproto/pkce.rb +125 -0
  54. data/lib/authproto/serialization/base.rb +258 -0
  55. data/lib/authproto/serialization/dpop_key.rb +38 -0
  56. data/lib/authproto/serialization/session.rb +88 -0
  57. data/lib/authproto/serialization/stored_nonce.rb +46 -0
  58. data/lib/authproto/serialization/token_set.rb +54 -0
  59. data/lib/authproto/server_metadata/authorization_server.rb +267 -0
  60. data/lib/authproto/server_metadata/origin_url.rb +71 -0
  61. data/lib/authproto/server_metadata/resource_server.rb +98 -0
  62. data/lib/authproto/server_metadata.rb +28 -0
  63. data/lib/authproto/state/session.rb +168 -0
  64. data/lib/authproto/state/session_manager.rb +162 -0
  65. data/lib/authproto/state/token_set.rb +101 -0
  66. data/lib/authproto/state.rb +61 -0
  67. data/lib/authproto/storage/interface.rb +121 -0
  68. data/lib/authproto/storage/key_builder.rb +76 -0
  69. data/lib/authproto/storage/memory.rb +222 -0
  70. data/lib/authproto/storage/redis.rb +156 -0
  71. data/lib/authproto/storage/sqlite.rb +281 -0
  72. data/lib/authproto/token/refresh.rb +414 -0
  73. data/lib/authproto/version.rb +8 -0
  74. data/lib/authproto.rb +18 -0
  75. data/sig/authproto/client.rbs +43 -0
  76. data/sig/authproto/client_metadata.rbs +113 -0
  77. data/sig/authproto/dependencies.rbs +19 -0
  78. data/sig/authproto/dpop/client.rbs +23 -0
  79. data/sig/authproto/dpop/key_manager.rbs +26 -0
  80. data/sig/authproto/dpop/nonce_manager.rbs +23 -0
  81. data/sig/authproto/dpop/proof_generator.rbs +40 -0
  82. data/sig/authproto/dpop/stored_nonce.rbs +10 -0
  83. data/sig/authproto/encryption.rbs +42 -0
  84. data/sig/authproto/http_client.rbs +45 -0
  85. data/sig/authproto/insecure_http_client.rbs +8 -0
  86. data/sig/authproto/localhost_server.rbs +30 -0
  87. data/sig/authproto/minisky_oauth.rbs +22 -0
  88. data/sig/authproto/par/client.rbs +25 -0
  89. data/sig/authproto/par/client_assertion.rbs +10 -0
  90. data/sig/authproto/par/request.rbs +73 -0
  91. data/sig/authproto/par/response.rbs +17 -0
  92. data/sig/authproto/par.rbs +7 -0
  93. data/sig/authproto/pkce.rbs +24 -0
  94. data/sig/authproto/serialization/base.rbs +36 -0
  95. data/sig/authproto/serialization/dpop_key.rbs +14 -0
  96. data/sig/authproto/serialization/session.rbs +19 -0
  97. data/sig/authproto/serialization/stored_nonce.rbs +14 -0
  98. data/sig/authproto/serialization/token_set.rbs +14 -0
  99. data/sig/authproto/server_metadata/authorization_server.rbs +71 -0
  100. data/sig/authproto/server_metadata/origin_url.rbs +21 -0
  101. data/sig/authproto/server_metadata/resource_server.rbs +27 -0
  102. data/sig/authproto/state/session.rbs +28 -0
  103. data/sig/authproto/state/session_manager.rbs +15 -0
  104. data/sig/authproto/state/token_set.rbs +40 -0
  105. data/sig/authproto/state.rbs +6 -0
  106. data/sig/authproto/storage/interface.rbs +20 -0
  107. data/sig/authproto/storage/key_builder.rbs +16 -0
  108. data/sig/authproto/storage/memory.rbs +22 -0
  109. data/sig/authproto/storage/redis.rbs +19 -0
  110. data/sig/authproto/storage/redis_client.rbs +11 -0
  111. data/sig/authproto/storage/sqlite.rbs +26 -0
  112. data/sig/authproto/token/refresh.rbs +47 -0
  113. data/sig/authproto/version.rbs +3 -0
  114. data/sig/authproto.rbs +54 -0
  115. metadata +200 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 77c4682515836e03bc41e1d03724f5ca2a85e65a11655b2af8a8ba09049a73fc
4
+ data.tar.gz: 0ba9433f0ee89b8617354d1e0245644f421fc1e7264597391b2efa5ebc015f79
5
+ SHA512:
6
+ metadata.gz: ebbd4f4c9df22f002bbe9be7c02b502bf4fcf5c056d4d0e9290a2c91dde8f03b4756e3b3db9f306cc1b9d5be6be183b88ace24ddb195733c37e92823ec0d5d78
7
+ data.tar.gz: 3b96e49a8ea9bbb555dab5996c0e6a53f0894616928c4416199f00561f2d9603cf327d0c868cf66501fd7b5982a8ec985d9e27e5032de274ef8daaccad58dbb4
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,31 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ SuggestExtensions: false
4
+ TargetRubyVersion: 3.2
5
+
6
+ Metrics/BlockLength:
7
+ Enabled: false
8
+
9
+ Metrics/ClassLength:
10
+ Enabled: false
11
+
12
+ Metrics/ModuleLength:
13
+ Enabled: false
14
+
15
+ Metrics/MethodLength:
16
+ Enabled: false
17
+
18
+ Metrics/AbcSize:
19
+ Enabled: false
20
+
21
+ Metrics/PerceivedComplexity:
22
+ Enabled: false
23
+
24
+ Metrics/CyclomaticComplexity:
25
+ Enabled: false
26
+
27
+ Style/StringLiterals:
28
+ EnforcedStyle: double_quotes
29
+
30
+ Style/StringLiteralsInInterpolation:
31
+ EnforcedStyle: double_quotes
data/.tm_properties ADDED
@@ -0,0 +1 @@
1
+ excludeInFolderSearch = "{$excludeInFolderSearch,coverage,doc}"
data/.yardopts ADDED
@@ -0,0 +1,4 @@
1
+ --protected
2
+ --no-private
3
+ --markup markdown
4
+ lib/**/*.rb
data/CHANGELOG.md ADDED
@@ -0,0 +1,52 @@
1
+ ## [0.2.5] - 2024-12-13
2
+
3
+ Fixed:
4
+
5
+ - Additional token refresh edge case handling
6
+
7
+ ## [0.2.4] - 2024-12-13
8
+
9
+ Fixed:
10
+
11
+ - Token refresh now correctly handles expired tokens
12
+
13
+ ## [0.2.2] - 2024-12-12
14
+
15
+ Added:
16
+
17
+ - Added support for did:web users
18
+
19
+ ## [0.2.1] - 2024-12-11
20
+
21
+ Fixed:
22
+
23
+ - Fixed a bug with access token hash generation
24
+
25
+ ## [0.2.0] - 2024-12-10
26
+
27
+ Added:
28
+
29
+ - Client#handle_callback now returns session did as part of the response
30
+
31
+ ## [0.1.0] - 2024-12-07
32
+
33
+ Added:
34
+
35
+ - Configurable storage backend system for managing OAuth state
36
+ - In-memory storage implementation included by default
37
+ - Redis storage implementation for production environments
38
+ - Thread-safe storage operations with atomic locks
39
+ - Storage encryption for sensitive data
40
+ - Automatic cleanup of expired tokens and session data
41
+ - Storage interface for custom backend implementations
42
+
43
+ Changed:
44
+
45
+ - Storage configuration is now required in AtprotoAuth.configure
46
+ - Default configuration uses thread-safe in-memory storage
47
+ - Session and token management now use configured storage backend
48
+ - Improved thread safety for all storage operations
49
+
50
+ ## [0.0.1] - 2024-12-05
51
+
52
+ - Initial release
data/MIT-LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Josh Huckabee, (c) 2026 Jakub Suder
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,304 @@
1
+ # AuthProto
2
+
3
+ [![Gem Version](https://img.shields.io/gem/v/authproto.svg)](https://rubygems.org/gems/authproto)
4
+ [![Documentation](https://img.shields.io/badge/docs-rdoc-blue.svg)](https://www.rubydoc.info/gems/authproto)
5
+
6
+ A Ruby implementation of the [AT Protocol OAuth specification](https://atproto.com/specs/oauth). This library provides support for both client and server-side implementations, with built-in security features including [DPoP](https://datatracker.ietf.org/doc/html/rfc9449), [PAR](https://datatracker.ietf.org/doc/html/rfc9126), and dynamic client registration.
7
+
8
+ > [!WARNING]
9
+ > I have inherited this gem from someone else, and haven't fully reviewed all code yet. Consider this an alpha version.
10
+
11
+
12
+ ## Features
13
+
14
+ - Complete AT Protocol OAuth 2.0 implementation
15
+ - Secure by default with mandatory DPoP and PKCE
16
+ - Support for confidential (backend) and public clients
17
+ - Thread-safe session and token management
18
+ - Comprehensive identity resolution and verification
19
+ - Automatic token refresh and session management
20
+ - Robust error handling and recovery mechanisms
21
+ - Configurable storage backends with built-in SQLite and Redis support
22
+ - Encrypted storage of sensitive data
23
+
24
+ ## Installation
25
+
26
+ Add this line to your application's Gemfile:
27
+
28
+ ```ruby
29
+ gem 'authproto'
30
+ ```
31
+
32
+ And then execute:
33
+
34
+ ```sh
35
+ bundle install
36
+ ```
37
+
38
+ Or install it yourself as:
39
+
40
+ ```sh
41
+ gem install authproto
42
+ ```
43
+
44
+ ## Requirements
45
+
46
+ - Ruby 3.3 or higher
47
+ - OpenSSL support
48
+ - For confidential clients: HTTPS-capable domain for client metadata hosting
49
+ - Optional: SQLite or Redis storage adapter gems for production use
50
+
51
+ ## Basic Usage
52
+
53
+ ### Configuration
54
+
55
+ ```ruby
56
+ require 'authproto'
57
+
58
+ AuthProto.configure do |config|
59
+ # Configure HTTP client settings
60
+ config.http_client = AuthProto::HTTPClient.new(
61
+ timeout: 10,
62
+ verify_ssl: true
63
+ )
64
+
65
+ # Set token lifetimes
66
+ config.default_token_lifetime = 300 # 5 minutes
67
+ config.dpop_nonce_lifetime = 300 # 5 minutes
68
+
69
+ # Configure storage backend (default is in-memory)
70
+ config.storage = AuthProto::Storage::Memory.new
71
+ end
72
+
73
+ # Storage adapter gems are optional dependencies. Add one of these:
74
+ gem 'sqlite3', '~> 2.9'
75
+ gem 'redis', '~> 5.4'
76
+ ```
77
+
78
+ ### Local HTTP debugging
79
+
80
+ For debugging a flow that needs both local HTTP and remote HTTPS (handle/PLC
81
+ resolution, metadata discovery and OAuth requests), explicitly select:
82
+
83
+ ```ruby
84
+ AuthProto.configure do |config|
85
+ config.http_client = AuthProto::InsecureHTTPClient.new(timeout: 10)
86
+ end
87
+ ```
88
+
89
+ `InsecureHTTPClient` accepts HTTP and HTTPS, including loopback and private-network
90
+ destinations, and permits redirects between them. It disables the regular client's
91
+ scheme/IP restrictions for development; HTTPS certificate verification stays enabled
92
+ by default. Timeouts, response size limits and request headers are inherited.
93
+
94
+ The regular `HTTPClient` accepts HTTPS and rejects loopback/private addresses.
95
+ Use it for remote OAuth servers, including when your application's callback is
96
+ local: the browser, rather than this HTTP client, follows the callback redirect.
97
+
98
+ Client metadata fetches call `get(url, follow_redirects: false)` and require HTTP
99
+ 200 with an `application/json` response. Custom HTTP clients must support this
100
+ keyword and return the initial response without following redirects when it is false.
101
+
102
+ Client metadata must explicitly set `token_endpoint_auth_method` to `none` for
103
+ public clients or `private_key_jwt` for confidential clients. Omitting it defaults
104
+ to `client_secret_basic` in OAuth metadata, which this library does not support.
105
+
106
+ ### Storage Backends
107
+
108
+ The library supports multiple storage backends for managing OAuth state:
109
+
110
+ #### In-Memory Storage (Default)
111
+
112
+ ```ruby
113
+ # Default configuration - good for development
114
+ AuthProto.configure do |config|
115
+ config.storage = AuthProto::Storage::Memory.new
116
+ end
117
+ ```
118
+
119
+ #### SQLite Storage
120
+
121
+ SQLite can be used for persistent storage in development or in production setups with
122
+ low-to-moderate write concurrency:
123
+
124
+ ```ruby
125
+ AuthProto.configure do |config|
126
+ config.storage = AuthProto::Storage::SQLite.new(
127
+ path: '/var/lib/my_app/authproto.sqlite3'
128
+ )
129
+ end
130
+ ```
131
+
132
+ Add the adapter gem to your Gemfile:
133
+
134
+ ```ruby
135
+ gem 'sqlite3', '~> 2.9'
136
+ ```
137
+
138
+ #### Redis Storage
139
+
140
+ Use Redis for production deployments with multiple hosts or write-heavy scenarios:
141
+
142
+ ```ruby
143
+ require 'redis'
144
+
145
+ AuthProto.configure do |config|
146
+ redis_client = Redis.new(
147
+ url: ENV['REDIS_URL'],
148
+ ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_PEER }
149
+ )
150
+
151
+ config.storage = AuthProto::Storage::Redis.new(
152
+ redis_client: redis_client
153
+ )
154
+ end
155
+ ```
156
+
157
+ Add the adapter gem to your Gemfile:
158
+
159
+ ```ruby
160
+ gem 'redis', '~> 5.4'
161
+ ```
162
+
163
+ #### Custom Storage Implementation
164
+ ```ruby
165
+ # Implement your own storage backend
166
+ class CustomStorage < AuthProto::Storage::Interface
167
+ def set(key, value, ttl: nil)
168
+ # Implementation
169
+ end
170
+
171
+ def get(key)
172
+ # Implementation
173
+ end
174
+
175
+ def delete(key)
176
+ # Implementation
177
+ end
178
+
179
+ def exists?(key)
180
+ # Implementation
181
+ end
182
+
183
+ def with_lock(key, ttl: 30)
184
+ # Implementation
185
+ end
186
+ end
187
+ ```
188
+
189
+ ### Confidential Client Example
190
+
191
+ Here's a basic example of using the library in a confidential client application:
192
+
193
+ ```ruby
194
+ # Initialize client with metadata
195
+ client = AuthProto::Client.new(
196
+ client_id: "https://app.example.com/oauth-client-metadata.json",
197
+ redirect_uri: "https://app.example.com/callback",
198
+ metadata: {
199
+ # Your client metadata...
200
+ }
201
+ )
202
+
203
+ # Start authorization flow
204
+ auth = client.authorize(
205
+ handle: "user.bsky.social",
206
+ scope: "atproto"
207
+ )
208
+
209
+ # Use auth[:url] to redirect user
210
+
211
+ # Handle callback
212
+ tokens = client.handle_callback(
213
+ code: params[:code],
214
+ state: params[:state],
215
+ iss: params[:iss]
216
+ )
217
+
218
+ # Make authenticated requests
219
+ headers = client.auth_headers(
220
+ session_id: tokens[:session_id],
221
+ method: "GET",
222
+ url: "https://api.example.com/resource"
223
+ )
224
+ ```
225
+
226
+ For a complete working example of a confidential client implementation, check out the example application in `examples/confidential_client/`. This Sinatra-based web application demonstrates:
227
+ - Complete OAuth flow implementation
228
+ - Session management
229
+ - DPoP token binding
230
+ - Making authenticated API requests
231
+ - Proper error handling
232
+ - Key generation and management
233
+
234
+ See `examples/confidential_client/README.md` for setup instructions and implementation details.
235
+
236
+ ### Public Client Example
237
+
238
+ ```ruby
239
+ client = AuthProto::Client.new(
240
+ client_id: "https://app.example.com/oauth-client-metadata.json",
241
+ redirect_uri: "https://app.example.com/callback"
242
+ )
243
+
244
+ # Browser will open authorization URL
245
+ auth = client.authorize(
246
+ handle: "user.bsky.social",
247
+ scope: "atproto"
248
+ )
249
+
250
+ # After callback, exchange code for tokens
251
+ tokens = client.handle_callback(
252
+ code: params[:code],
253
+ state: params[:state],
254
+ iss: params[:iss]
255
+ )
256
+ ```
257
+
258
+ ## Features In Detail
259
+
260
+ ### Identity Resolution
261
+
262
+ The library uses DIDKit for AT Protocol identity resolution:
263
+
264
+ - Handle to DID resolution (DNS-based or HTTP fallback)
265
+ - DID document fetching and validation
266
+ - PDS (Personal Data Server) location verification
267
+ - Bidirectional handle verification
268
+ - Authorization server binding verification
269
+
270
+ ### Token & Session Management
271
+
272
+ Comprehensive token lifecycle management:
273
+
274
+ - Secure token storage with encryption
275
+ - Automatic token refresh
276
+ - DPoP proof generation and binding
277
+ - Session state tracking
278
+ - Cleanup of expired sessions
279
+
280
+ ### Security Features
281
+
282
+ Built-in security best practices:
283
+
284
+ - Mandatory PKCE for all flows
285
+ - DPoP token binding
286
+ - Constant-time token comparisons
287
+ - Thread-safe state management
288
+ - Protection against SSRF attacks
289
+ - Secure encrypted token storage
290
+ - Atomic storage operations with locking
291
+
292
+ ## Development
293
+
294
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` (or `bundle exec rake spec`) to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
295
+
296
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
297
+
298
+ ## Contributing
299
+
300
+ Bug reports and pull requests are welcome on GitHub at https://github.com/mackuba/authproto.
301
+
302
+ ## License
303
+
304
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: %i[spec]
data/SECURITY.md ADDED
@@ -0,0 +1,16 @@
1
+ # Security Policy
2
+
3
+ ## How To Report a Vulnerability
4
+
5
+ If you find a potential vulnerability in one of my projects, it's recommended not to report it through a standard publicly-readable issue report, in order to avoid giving possible clues to any potential attackers who could abuse it before it's fixed (see: ["Just a rumour of a bug is enough to find a security exploit these days"](https://anil.recoil.org/notes/rumour-is-the-exploit)).
6
+
7
+ You can use one of these to contact me instead:
8
+
9
+ - [@mackuba.eu](https://bsky.app/profile/did:plc:oio4hkxaop4ao4wz2pp3f4cr) on Bluesky (my DMs should be open, or mention me discretely with a request for contact)
10
+ - [@mackuba@martianbase.net](https://martianbase.net/@mackuba) on Mastodon (my personal instance)
11
+ - email: mackuba `@` protonmail.ch (optionally with [this PGP key](https://mail-api.proton.me/pks/lookup?op=get&search=mackuba@protonmail.ch))
12
+ - ["Report a vulnerability"](https://github.com/mackuba/didkit/security/advisories/new) form on GitHub
13
+
14
+ I do not check my Twitter/X or LinkedIn accounts regularly.
15
+
16
+ Note: please don't submit AI-reported issues that have not been verified manually :)
@@ -0,0 +1,5 @@
1
+ .env
2
+ /config/client-metadata.json
3
+ /config/keys.json
4
+ /db/
5
+ /public/client-metadata.json
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "authproto", path: "../.."
6
+ gem "dotenv"
7
+ gem "faraday"
8
+ gem "json"
9
+ gem "puma"
10
+ gem "rackup"
11
+ gem "redis"
12
+ gem "sinatra"
13
+ gem "sinatra-contrib"
14
+ gem "sqlite3", "~> 2.9"
@@ -0,0 +1,88 @@
1
+ PATH
2
+ remote: ../..
3
+ specs:
4
+ authproto (0.2.5)
5
+ jose (~> 1.2)
6
+ jwt (~> 3.3)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ base64 (0.3.0)
12
+ concurrent-ruby (1.3.8)
13
+ connection_pool (3.0.2)
14
+ dotenv (3.2.0)
15
+ faraday (2.14.3)
16
+ faraday-net_http (>= 2.0, < 3.5)
17
+ json
18
+ logger
19
+ faraday-net_http (3.4.4)
20
+ net-http (~> 0.5)
21
+ immutable-ruby (0.2.0)
22
+ concurrent-ruby (~> 1.1)
23
+ sorted_set (~> 1.0)
24
+ jose (1.2.0)
25
+ base64
26
+ immutable-ruby
27
+ json (2.21.1)
28
+ jwt (3.3.0)
29
+ base64
30
+ logger (1.7.0)
31
+ multi_json (1.21.1)
32
+ mustermann (3.1.1)
33
+ net-http (0.9.1)
34
+ uri (>= 0.11.1)
35
+ nio4r (2.7.5)
36
+ puma (8.0.2)
37
+ nio4r (~> 2.0)
38
+ rack (3.2.6)
39
+ rack-protection (4.2.1)
40
+ base64 (>= 0.1.0)
41
+ logger (>= 1.6.0)
42
+ rack (>= 3.0.0, < 4)
43
+ rack-session (2.1.2)
44
+ base64 (>= 0.1.0)
45
+ rack (>= 3.0.0)
46
+ rackup (2.3.1)
47
+ rack (>= 3)
48
+ rbtree (0.4.7)
49
+ redis (5.4.1)
50
+ redis-client (>= 0.22.0)
51
+ redis-client (0.30.1)
52
+ connection_pool
53
+ sinatra (4.2.1)
54
+ logger (>= 1.6.0)
55
+ mustermann (~> 3.0)
56
+ rack (>= 3.0.0, < 4)
57
+ rack-protection (= 4.2.1)
58
+ rack-session (>= 2.0.0, < 3)
59
+ tilt (~> 2.0)
60
+ sinatra-contrib (4.2.1)
61
+ multi_json (>= 0.0.2)
62
+ mustermann (~> 3.0)
63
+ rack-protection (= 4.2.1)
64
+ sinatra (= 4.2.1)
65
+ tilt (~> 2.0)
66
+ sorted_set (1.1.0)
67
+ rbtree
68
+ sqlite3 (2.9.5-arm64-darwin)
69
+ tilt (2.8.0)
70
+ uri (1.1.1)
71
+
72
+ PLATFORMS
73
+ arm64-darwin-24
74
+
75
+ DEPENDENCIES
76
+ authproto!
77
+ dotenv
78
+ faraday
79
+ json
80
+ puma
81
+ rackup
82
+ redis
83
+ sinatra
84
+ sinatra-contrib
85
+ sqlite3 (~> 2.9)
86
+
87
+ BUNDLED WITH
88
+ 4.0.17