kiosk-server 0.5.20

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 (127) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +549 -0
  3. data/LICENSE.txt +202 -0
  4. data/README.md +635 -0
  5. data/app/channels/kiosk_events.rb +138 -0
  6. data/app/controllers/kiosk/server/application_controller.rb +17 -0
  7. data/app/controllers/kiosk/server/assistants_controller.rb +96 -0
  8. data/app/controllers/kiosk/server/auth_controller.rb +187 -0
  9. data/app/controllers/kiosk/server/device_verify_controller.rb +101 -0
  10. data/app/controllers/kiosk/server/discovery_controller.rb +66 -0
  11. data/app/controllers/kiosk/server/jwks_controller.rb +15 -0
  12. data/app/controllers/kiosk/server/kyc_attestation_controller.rb +69 -0
  13. data/app/controllers/kiosk/server/kyc_callback_controller.rb +15 -0
  14. data/app/controllers/kiosk/server/oauth_device_authorization_controller.rb +73 -0
  15. data/app/controllers/kiosk/server/oauth_token_controller.rb +59 -0
  16. data/app/controllers/kiosk/server/open_api_controller.rb +20 -0
  17. data/app/controllers/kiosk/server/payment_setup_controller.rb +31 -0
  18. data/app/controllers/kiosk/server/verb_controller.rb +61 -0
  19. data/app/controllers/kiosk/server/wire_controller.rb +43 -0
  20. data/app/models/kiosk/cart_mandate.rb +21 -0
  21. data/app/models/kiosk/server/application_record.rb +10 -0
  22. data/app/models/kiosk/settlement.rb +12 -0
  23. data/app/models/kiosk/visit.rb +13 -0
  24. data/app/views/kiosk/server/assistants/show.html.erb +94 -0
  25. data/app/views/kiosk/server/device_verify/decided.html.erb +14 -0
  26. data/app/views/kiosk/server/device_verify/show.html.erb +53 -0
  27. data/lib/generators/kiosk/install/install_generator.rb +125 -0
  28. data/lib/generators/kiosk/install/templates/create_kiosk_auth_challenges.rb.tt +16 -0
  29. data/lib/generators/kiosk/install/templates/create_kiosk_device_authorizations.rb.tt +17 -0
  30. data/lib/generators/kiosk/install/templates/create_kiosk_events.rb.tt +22 -0
  31. data/lib/generators/kiosk/install/templates/create_kiosk_identity_tables.rb.tt +16 -0
  32. data/lib/generators/kiosk/install/templates/create_kiosk_kyc_attributes.rb.tt +20 -0
  33. data/lib/generators/kiosk/install/templates/create_kiosk_mandates.rb.tt +21 -0
  34. data/lib/generators/kiosk/install/templates/create_kiosk_pow_spent.rb.tt +16 -0
  35. data/lib/generators/kiosk/install/templates/create_kiosk_refunds.rb.tt +16 -0
  36. data/lib/generators/kiosk/install/templates/create_kiosk_revocations.rb.tt +16 -0
  37. data/lib/generators/kiosk/install/templates/create_kiosk_schema.rb.tt +17 -0
  38. data/lib/generators/kiosk/install/templates/create_kiosk_visits.rb.tt +16 -0
  39. data/lib/generators/kiosk/install/templates/initializer.rb.tt +53 -0
  40. data/lib/kiosk/handler.rb +43 -0
  41. data/lib/kiosk/owned.rb +17 -0
  42. data/lib/kiosk/payable.rb +90 -0
  43. data/lib/kiosk/server/account_binding.rb +188 -0
  44. data/lib/kiosk/server/account_holder_gate.rb +58 -0
  45. data/lib/kiosk/server/action_event.rb +60 -0
  46. data/lib/kiosk/server/actions.rb +14 -0
  47. data/lib/kiosk/server/agent_identity_providers/default_agent_idp.rb +89 -0
  48. data/lib/kiosk/server/agent_login.rb +49 -0
  49. data/lib/kiosk/server/agent_registration.rb +88 -0
  50. data/lib/kiosk/server/argument_decoder.rb +260 -0
  51. data/lib/kiosk/server/audit_sink.rb +42 -0
  52. data/lib/kiosk/server/auth_challenge.rb +33 -0
  53. data/lib/kiosk/server/auth_challenge_stores.rb +74 -0
  54. data/lib/kiosk/server/auth_toll.rb +44 -0
  55. data/lib/kiosk/server/binding_module_gate.rb +25 -0
  56. data/lib/kiosk/server/caller_timezone.rb +50 -0
  57. data/lib/kiosk/server/column_spending_cap.rb +26 -0
  58. data/lib/kiosk/server/configuration_extension.rb +328 -0
  59. data/lib/kiosk/server/controller_verb.rb +63 -0
  60. data/lib/kiosk/server/current_request.rb +31 -0
  61. data/lib/kiosk/server/cursor.rb +33 -0
  62. data/lib/kiosk/server/device_authorization.rb +136 -0
  63. data/lib/kiosk/server/device_authorization_stores.rb +184 -0
  64. data/lib/kiosk/server/device_code_grant.rb +145 -0
  65. data/lib/kiosk/server/device_verification.rb +46 -0
  66. data/lib/kiosk/server/engine.rb +203 -0
  67. data/lib/kiosk/server/errors.rb +339 -0
  68. data/lib/kiosk/server/event_stores.rb +124 -0
  69. data/lib/kiosk/server/events.rb +86 -0
  70. data/lib/kiosk/server/events_cable.rb +102 -0
  71. data/lib/kiosk/server/events_connection.rb +170 -0
  72. data/lib/kiosk/server/executor/repeat.rb +42 -0
  73. data/lib/kiosk/server/executor/spending_cap.rb +102 -0
  74. data/lib/kiosk/server/executor.rb +397 -0
  75. data/lib/kiosk/server/failure_log.rb +28 -0
  76. data/lib/kiosk/server/handler_mixin.rb +418 -0
  77. data/lib/kiosk/server/handler_registrations.rb +57 -0
  78. data/lib/kiosk/server/handler_serving.rb +197 -0
  79. data/lib/kiosk/server/headers.rb +82 -0
  80. data/lib/kiosk/server/headers_middleware.rb +31 -0
  81. data/lib/kiosk/server/identity_resolution.rb +20 -0
  82. data/lib/kiosk/server/issuer_middleware.rb +22 -0
  83. data/lib/kiosk/server/jwks.rb +14 -0
  84. data/lib/kiosk/server/jwt_issuer.rb +98 -0
  85. data/lib/kiosk/server/kyc.rb +261 -0
  86. data/lib/kiosk/server/kyc_verifier.rb +106 -0
  87. data/lib/kiosk/server/link_code.rb +90 -0
  88. data/lib/kiosk/server/linked_assistants.rb +116 -0
  89. data/lib/kiosk/server/mandate_verifier.rb +221 -0
  90. data/lib/kiosk/server/open_api.rb +543 -0
  91. data/lib/kiosk/server/page.rb +19 -0
  92. data/lib/kiosk/server/payment_claim.rb +293 -0
  93. data/lib/kiosk/server/payment_setup.rb +102 -0
  94. data/lib/kiosk/server/pop_verifier.rb +87 -0
  95. data/lib/kiosk/server/pow_gate.rb +121 -0
  96. data/lib/kiosk/server/pow_spent_stores.rb +96 -0
  97. data/lib/kiosk/server/pow_toll.rb +136 -0
  98. data/lib/kiosk/server/queries.rb +14 -0
  99. data/lib/kiosk/server/reputation_factors.rb +38 -0
  100. data/lib/kiosk/server/request_validation.rb +171 -0
  101. data/lib/kiosk/server/response_validation.rb +45 -0
  102. data/lib/kiosk/server/result.rb +25 -0
  103. data/lib/kiosk/server/revocation_stores.rb +57 -0
  104. data/lib/kiosk/server/routing.rb +76 -0
  105. data/lib/kiosk/server/schema_definitions.rb +351 -0
  106. data/lib/kiosk/server/schema_document.rb +116 -0
  107. data/lib/kiosk/server/schema_slots.rb +119 -0
  108. data/lib/kiosk/server/schemas/auth.schema.json +135 -0
  109. data/lib/kiosk/server/schemas/binding.schema.json +145 -0
  110. data/lib/kiosk/server/schemas/kyc.schema.json +114 -0
  111. data/lib/kiosk/server/schemas/mandates.schema.json +75 -0
  112. data/lib/kiosk/server/schemas/pow.schema.json +94 -0
  113. data/lib/kiosk/server/session_context.rb +88 -0
  114. data/lib/kiosk/server/settled_spend.rb +21 -0
  115. data/lib/kiosk/server/signing_key.rb +82 -0
  116. data/lib/kiosk/server/verb_registry.rb +77 -0
  117. data/lib/kiosk/server/verb_vocabulary.rb +163 -0
  118. data/lib/kiosk/server/verb_wire.rb +85 -0
  119. data/lib/kiosk/server/version.rb +7 -0
  120. data/lib/kiosk/server/well_known.rb +416 -0
  121. data/lib/kiosk/server/wire_rendering.rb +116 -0
  122. data/lib/kiosk/server/wrong_door.rb +42 -0
  123. data/lib/kiosk/server.rb +42 -0
  124. data/lib/kiosk/skill_link.rb +16 -0
  125. data/listen.py +278 -0
  126. data/requirements.txt +1 -0
  127. metadata +349 -0
data/listen.py ADDED
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env python3
2
+ """Kiosk event-stream listener — the pinned reference client.
3
+
4
+ Opens ONE WebSocket to an operator's `events_url`, subscribes to the topics you
5
+ name, and writes every message it receives as one JSON line on stdout. The
6
+ operator pushes when something happens, so there is nothing to poll and no
7
+ cadence to invent.
8
+
9
+ python3 listen.py --url wss://shop.example/kiosk/events \
10
+ --token-file ~/.kiosk/https_shop.example_443/token \
11
+ --topic order_delivery:<order-id>
12
+
13
+ The bearer token is read from a file, never from the command line, where every
14
+ process listing and shell history would show it.
15
+
16
+ WAKE ON THE EVENT: run it as a background process your runtime TRACKS and wakes
17
+ you on when it exits. With `--until-event` it prints the first event and exits 0
18
+ the moment it arrives, or exits 5 at `--max-seconds` with nothing. On waking, act
19
+ on the event, tell your human, and start it again with `--since <its id>`. Keep
20
+ `--max-seconds` below the longest your runtime lets a background process live. A
21
+ process the runtime does not track -- nohup, `&`, setsid -- wakes nobody, and
22
+ neither does a line landing in a file.
23
+
24
+ python3 listen.py --url … --token-file … --topic kyc_verification \
25
+ --until-event --max-seconds 300
26
+
27
+ Each line is a JSON object with a `type`:
28
+
29
+ {"type":"open"} the socket is up and authenticated
30
+ {"type":"subscribed","topic":…,"head":…,"truncated":…}
31
+ {"type":"event","id":…,"topic":…,"subject":…,"occurred_at":…,"data":{…}}
32
+ {"type":"rejected","topic":…} that topic is not yours to read
33
+ {"type":"unsubscribed","topic":…,"reason":…} you lost reach mid-stream
34
+ {"type":"disconnect","reason":…,"reconnect":…}
35
+ {"type":"reconnecting","in":…,"since":…}
36
+ {"type":"error","message":…}
37
+
38
+ EXIT CODES: 0 you asked it to stop (--max-seconds), or --until-event got its
39
+ event; 2 the arguments or the URL are wrong; 3 the operator will not have this
40
+ token back and no --token-command was given — mint a fresh one and start it
41
+ again; 4 nothing you asked for can arrive: every topic you named was refused,
42
+ or the origin serves no event stream (`501 module_not_served`); 5
43
+ --until-event reached the deadline with nothing.
44
+
45
+ It needs `websockets` from PyPI (>= 12, the release that added the threading
46
+ client). Add it to the same venv the skill already has you create:
47
+
48
+ pip install 'websockets>=12'
49
+
50
+ Do NOT replace this file with a client of your own. The subprotocol token, the
51
+ string-inside-a-string `identifier`, and the resume contract are each a place a
52
+ hand-rolled client is dropped with no diagnostic, and you would read that
53
+ silence as "nothing happened".
54
+ """
55
+
56
+ import argparse
57
+ import json
58
+ import os
59
+ import random
60
+ import subprocess
61
+ import sys
62
+ import time
63
+ from urllib.parse import urlencode, urlsplit, urlunsplit
64
+
65
+ import websockets
66
+ from websockets.sync.client import connect
67
+
68
+ SUBPROTOCOL = "actioncable-v1-json"
69
+ # The operator's own beat is one ping every thirty seconds. Three missed in a
70
+ # row is a socket that is gone without having said so — half-open TCP, a dozing
71
+ # laptop, an edge that dropped us — and the only way to find out is to stop
72
+ # waiting.
73
+ IDLE_TIMEOUT = 95
74
+ BACKOFF_CAP = 30
75
+
76
+
77
+ def emit(**line):
78
+ """One JSON object per line, flushed, so a tail sees it immediately."""
79
+ sys.stdout.write(json.dumps(line, separators=(",", ":")) + "\n")
80
+ sys.stdout.flush()
81
+
82
+
83
+ def problem_code(response):
84
+ """The `code` of a refused upgrade's problem document, when it carries one."""
85
+ try:
86
+ return json.loads(response.body)["code"]
87
+ except (TypeError, ValueError, KeyError):
88
+ return None
89
+
90
+
91
+ def stream_url(url, topics, since):
92
+ """`?topic=` is how you subscribe: the operator reads it on connect and
93
+ confirms each one, so a round trip per topic is not needed."""
94
+ query = [("topic", ",".join(topics))]
95
+ if since is not None:
96
+ query.append(("since", str(since)))
97
+ parts = urlsplit(url)
98
+ return urlunsplit((parts.scheme, parts.netloc, parts.path, urlencode(query), ""))
99
+
100
+
101
+ def read_frames(socket, state, deadline):
102
+ """Drain one connection, and say what to do next.
103
+
104
+ "retry" reconnect · "stop" --max-seconds is up · "event" --until-event got
105
+ its event · "credential" the operator will not have this token back ·
106
+ "unreadable" every topic was refused.
107
+
108
+ The read is bounded rather than blocking forever: a deadline nothing
109
+ checks is not a deadline, and a socket that died without saying so looks
110
+ exactly like a quiet one.
111
+ """
112
+ while True:
113
+ budget = IDLE_TIMEOUT
114
+ if deadline:
115
+ budget = min(budget, deadline - time.monotonic())
116
+ if budget <= 0:
117
+ return "stop"
118
+ try:
119
+ raw = socket.recv(timeout=budget)
120
+ except TimeoutError:
121
+ # The deadline, or three of the operator's beats missed — a socket
122
+ # that died without saying so. Neither is an error worth a line.
123
+ return "stop" if deadline and time.monotonic() >= deadline else "retry"
124
+ frame = json.loads(raw)
125
+ kind = frame.get("type")
126
+
127
+ if kind in ("ping", "welcome"):
128
+ continue
129
+
130
+ if kind == "confirm_subscription":
131
+ state["confirmed"] += 1
132
+ continue
133
+
134
+ if kind == "reject_subscription":
135
+ emit(type="rejected", topic=topic_of(frame))
136
+ state["rejected"] += 1
137
+ # EVERY topic refused and none confirmed: there is nothing on
138
+ # this socket to wait for, ever. Say so rather than sit on it.
139
+ if state["confirmed"] == 0 and state["rejected"] >= state["wanted"]:
140
+ return "unreadable"
141
+ continue
142
+
143
+ if kind == "disconnect":
144
+ emit(type="disconnect", reason=frame.get("reason"),
145
+ reconnect=frame.get("reconnect", True))
146
+ # `reconnect: false` is the operator saying this credential is done:
147
+ # it expired, or the human revoked the assistant. A retry with the
148
+ # same bearer loses the same argument, so mint a new one or stop.
149
+ if frame.get("reconnect", True):
150
+ return "retry"
151
+ return "retry" if state["refresh"] else "credential"
152
+
153
+ message = frame.get("message")
154
+ if not isinstance(message, dict):
155
+ continue
156
+
157
+ if message.get("type") == "subscribed":
158
+ # `head` is where the operator's tail stood when this subscription
159
+ # opened. Adopt it as the resume floor NOW rather than waiting for
160
+ # a first event: a socket that drops before anything arrives would
161
+ # otherwise reconnect asking for nothing in particular, and every
162
+ # event emitted during the gap would be missed in silence.
163
+ if message.get("head") is not None:
164
+ state["since"] = max(state["since"] or 0, int(message["head"]))
165
+ emit(**message)
166
+ continue
167
+
168
+ if message.get("type") == "unsubscribed":
169
+ emit(**message)
170
+ continue
171
+
172
+ # An event. Its `id` is per-operator and monotonic, so the highest one
173
+ # seen is exactly what `since` wants after a drop.
174
+ if message.get("id") is not None:
175
+ state["since"] = max(state["since"] or 0, int(message["id"]))
176
+ emit(type="event", **message)
177
+ # The one-shot wait is over the moment the thing you waited for lands.
178
+ # A `subscribed` confirmation is not that, and neither is a beat.
179
+ if state["one_shot"]:
180
+ return "event"
181
+
182
+
183
+ def topic_of(frame):
184
+ try:
185
+ return json.loads(frame.get("identifier") or "{}").get("topic")
186
+ except ValueError:
187
+ return None
188
+
189
+
190
+ def main():
191
+ parser = argparse.ArgumentParser(description="Kiosk event-stream listener")
192
+ parser.add_argument("--url", required=True, help="the operator's events_url")
193
+ parser.add_argument("--token-file", required=True, metavar="PATH",
194
+ help="a file holding your bearer token")
195
+ parser.add_argument("--topic", action="append", required=True, metavar="NAME[:SUBJECT]",
196
+ help="repeatable; NAME:SUBJECT narrows to one row")
197
+ parser.add_argument("--since", type=int, help="resume after this event id")
198
+ parser.add_argument("--token-command",
199
+ help="shell command printing a fresh bearer token; run when the "
200
+ "operator says this one will not be accepted back")
201
+ parser.add_argument("--max-seconds", type=float, help="stop after this long")
202
+ parser.add_argument("--until-event", action="store_true",
203
+ help="exit 0 on the first event, 5 at --max-seconds with none")
204
+ args = parser.parse_args()
205
+
206
+ if urlsplit(args.url).scheme not in ("ws", "wss"):
207
+ parser.error("--url must be ws:// or wss://")
208
+ if args.until_event and not args.max_seconds:
209
+ parser.error("--until-event needs --max-seconds: a wait with no deadline never returns")
210
+
211
+ try:
212
+ with open(os.path.expanduser(args.token_file)) as file:
213
+ token = file.read().strip()
214
+ except OSError as error:
215
+ parser.error(f"--token-file: {error.strerror}")
216
+
217
+ state = {"since": args.since, "token": token, "refresh": args.token_command,
218
+ "wanted": len(args.topic), "confirmed": 0, "rejected": 0,
219
+ "one_shot": args.until_event}
220
+ deadline = time.monotonic() + args.max_seconds if args.max_seconds else None
221
+ attempt = 0
222
+
223
+ while True:
224
+ if deadline and time.monotonic() >= deadline:
225
+ return 5 if args.until_event else 0
226
+ renew = True
227
+ try:
228
+ with connect(stream_url(args.url, args.topic, state["since"]),
229
+ subprotocols=[SUBPROTOCOL],
230
+ additional_headers={"Authorization": f"Bearer {state['token']}"},
231
+ open_timeout=15, close_timeout=5) as socket:
232
+ emit(type="open")
233
+ attempt = 0
234
+ state["confirmed"] = state["rejected"] = 0
235
+ verdict = read_frames(socket, state, deadline)
236
+ if verdict == "event":
237
+ return 0
238
+ if verdict == "stop":
239
+ return 5 if args.until_event else 0
240
+ if verdict == "unreadable":
241
+ return 4
242
+ if verdict == "credential":
243
+ return 3
244
+ except KeyboardInterrupt:
245
+ return 0
246
+ except websockets.InvalidStatus as error:
247
+ status = error.response.status_code
248
+ code = problem_code(error.response)
249
+ emit(type="error", message=f"upgrade refused: {status}" + (f" {code}" if code else ""))
250
+ # 501: this origin serves no event stream, for any credential.
251
+ if status == 501:
252
+ return 4
253
+ if status not in (401, 403):
254
+ renew = False
255
+ elif state["refresh"] is None:
256
+ return 3
257
+ except Exception as error: # noqa: BLE001 — every transport fault is one retry
258
+ emit(type="error", message=f"{type(error).__name__}: {error}")
259
+
260
+ if renew and state["refresh"] is not None:
261
+ fresh = subprocess.run(state["refresh"], shell=True, capture_output=True,
262
+ text=True, check=False)
263
+ if fresh.returncode == 0 and fresh.stdout.strip():
264
+ state["token"] = fresh.stdout.strip()
265
+ else:
266
+ emit(type="error", message="--token-command produced no token")
267
+ return 3
268
+
269
+ attempt += 1
270
+ wait = min(2 ** (attempt - 1), BACKOFF_CAP) * (0.5 + random.random())
271
+ if deadline:
272
+ wait = min(wait, max(0.0, deadline - time.monotonic()))
273
+ emit(type="reconnecting", **{"in": round(wait, 2), "since": state["since"]})
274
+ time.sleep(wait)
275
+
276
+
277
+ if __name__ == "__main__":
278
+ sys.exit(main())
data/requirements.txt ADDED
@@ -0,0 +1 @@
1
+ websockets>=12
metadata ADDED
@@ -0,0 +1,349 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kiosk-server
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.20
5
+ platform: ruby
6
+ authors:
7
+ - Phil Pirozhkov
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: kiosk-core
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: 0.5.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: 0.5.0
26
+ - !ruby/object:Gem::Dependency
27
+ name: jwt
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '2.8'
33
+ - - "<"
34
+ - !ruby/object:Gem::Version
35
+ version: '4.0'
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '2.8'
43
+ - - "<"
44
+ - !ruby/object:Gem::Version
45
+ version: '4.0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: base64
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ type: :runtime
54
+ prerelease: false
55
+ version_requirements: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ - !ruby/object:Gem::Dependency
61
+ name: zeitwerk
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '2.6'
67
+ type: :runtime
68
+ prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '2.6'
74
+ - !ruby/object:Gem::Dependency
75
+ name: json_schemer
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '2.3'
81
+ - - "<"
82
+ - !ruby/object:Gem::Version
83
+ version: '3.0'
84
+ type: :runtime
85
+ prerelease: false
86
+ version_requirements: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '2.3'
91
+ - - "<"
92
+ - !ruby/object:Gem::Version
93
+ version: '3.0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: railties
96
+ requirement: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '8.1'
101
+ type: :runtime
102
+ prerelease: false
103
+ version_requirements: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - "~>"
106
+ - !ruby/object:Gem::Version
107
+ version: '8.1'
108
+ - !ruby/object:Gem::Dependency
109
+ name: actionpack
110
+ requirement: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - "~>"
113
+ - !ruby/object:Gem::Version
114
+ version: '8.1'
115
+ type: :runtime
116
+ prerelease: false
117
+ version_requirements: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - "~>"
120
+ - !ruby/object:Gem::Version
121
+ version: '8.1'
122
+ - !ruby/object:Gem::Dependency
123
+ name: actioncable
124
+ requirement: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - "~>"
127
+ - !ruby/object:Gem::Version
128
+ version: '8.1'
129
+ type: :runtime
130
+ prerelease: false
131
+ version_requirements: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - "~>"
134
+ - !ruby/object:Gem::Version
135
+ version: '8.1'
136
+ - !ruby/object:Gem::Dependency
137
+ name: activerecord
138
+ requirement: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - "~>"
141
+ - !ruby/object:Gem::Version
142
+ version: '8.1'
143
+ type: :runtime
144
+ prerelease: false
145
+ version_requirements: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - "~>"
148
+ - !ruby/object:Gem::Version
149
+ version: '8.1'
150
+ - !ruby/object:Gem::Dependency
151
+ name: activesupport
152
+ requirement: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - "~>"
155
+ - !ruby/object:Gem::Version
156
+ version: '8.1'
157
+ type: :runtime
158
+ prerelease: false
159
+ version_requirements: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - "~>"
162
+ - !ruby/object:Gem::Version
163
+ version: '8.1'
164
+ description: |
165
+ kiosk-server is the host-side surface for Kiosk. The full surface ships:
166
+
167
+ - The controllers — the per-verb wire (GET <endpoint>/<query-name>,
168
+ POST <endpoint>/<action-name>) and the reserved endpoints
169
+ (/kiosk/schema, /kiosk/pay), a derived OpenAPI description of both,
170
+ the register/login proof-of-possession auth plane, JWKS, the KYC
171
+ attestation endpoint, agents.txt / agents.json / kiosk.json
172
+ discovery, and the account-binding ceremony (RFC 8628-shaped device
173
+ authorization, the possession-proof-gated token poll, the verify and
174
+ «Link an assistant» pages).
175
+ - Kiosk::Server::Executor — dispatches a resolved command to the
176
+ queries and actions the host registered.
177
+ - Agent registration and login, with a pluggable agent-IdP.
178
+ - The PoW gate that enforces a kiosk-reputation policy's challenge
179
+ (soft dependency; zero overhead when no policy is set).
180
+ - A Rack middleware injecting the Kiosk-Server-Version /
181
+ Kiosk-API-Version / Kiosk-Min-Client response headers, a pure-Ruby
182
+ builder for the discovery documents, SQL generators for the
183
+ canonical schema migrations, and a `kiosk:install` generator that
184
+ lays down the initializer and the migrations.
185
+
186
+ The Rails engine serves that whole surface from one `kiosk` block in
187
+ config/routes.rb, which mounts it at Kiosk.configuration.mount_path —
188
+ drawing the wire/auth/JWKS/KYC/binding routes under the mount and
189
+ installing the root-relative discovery routes (agents.txt, .well-known)
190
+ into the host — then one route per query and action the block names. It
191
+ also auto-injects the headers middleware.
192
+ email:
193
+ - hello@fili.pp.ru
194
+ executables: []
195
+ extensions: []
196
+ extra_rdoc_files: []
197
+ files:
198
+ - CHANGELOG.md
199
+ - LICENSE.txt
200
+ - README.md
201
+ - app/channels/kiosk_events.rb
202
+ - app/controllers/kiosk/server/application_controller.rb
203
+ - app/controllers/kiosk/server/assistants_controller.rb
204
+ - app/controllers/kiosk/server/auth_controller.rb
205
+ - app/controllers/kiosk/server/device_verify_controller.rb
206
+ - app/controllers/kiosk/server/discovery_controller.rb
207
+ - app/controllers/kiosk/server/jwks_controller.rb
208
+ - app/controllers/kiosk/server/kyc_attestation_controller.rb
209
+ - app/controllers/kiosk/server/kyc_callback_controller.rb
210
+ - app/controllers/kiosk/server/oauth_device_authorization_controller.rb
211
+ - app/controllers/kiosk/server/oauth_token_controller.rb
212
+ - app/controllers/kiosk/server/open_api_controller.rb
213
+ - app/controllers/kiosk/server/payment_setup_controller.rb
214
+ - app/controllers/kiosk/server/verb_controller.rb
215
+ - app/controllers/kiosk/server/wire_controller.rb
216
+ - app/models/kiosk/cart_mandate.rb
217
+ - app/models/kiosk/server/application_record.rb
218
+ - app/models/kiosk/settlement.rb
219
+ - app/models/kiosk/visit.rb
220
+ - app/views/kiosk/server/assistants/show.html.erb
221
+ - app/views/kiosk/server/device_verify/decided.html.erb
222
+ - app/views/kiosk/server/device_verify/show.html.erb
223
+ - lib/generators/kiosk/install/install_generator.rb
224
+ - lib/generators/kiosk/install/templates/create_kiosk_auth_challenges.rb.tt
225
+ - lib/generators/kiosk/install/templates/create_kiosk_device_authorizations.rb.tt
226
+ - lib/generators/kiosk/install/templates/create_kiosk_events.rb.tt
227
+ - lib/generators/kiosk/install/templates/create_kiosk_identity_tables.rb.tt
228
+ - lib/generators/kiosk/install/templates/create_kiosk_kyc_attributes.rb.tt
229
+ - lib/generators/kiosk/install/templates/create_kiosk_mandates.rb.tt
230
+ - lib/generators/kiosk/install/templates/create_kiosk_pow_spent.rb.tt
231
+ - lib/generators/kiosk/install/templates/create_kiosk_refunds.rb.tt
232
+ - lib/generators/kiosk/install/templates/create_kiosk_revocations.rb.tt
233
+ - lib/generators/kiosk/install/templates/create_kiosk_schema.rb.tt
234
+ - lib/generators/kiosk/install/templates/create_kiosk_visits.rb.tt
235
+ - lib/generators/kiosk/install/templates/initializer.rb.tt
236
+ - lib/kiosk/handler.rb
237
+ - lib/kiosk/owned.rb
238
+ - lib/kiosk/payable.rb
239
+ - lib/kiosk/server.rb
240
+ - lib/kiosk/server/account_binding.rb
241
+ - lib/kiosk/server/account_holder_gate.rb
242
+ - lib/kiosk/server/action_event.rb
243
+ - lib/kiosk/server/actions.rb
244
+ - lib/kiosk/server/agent_identity_providers/default_agent_idp.rb
245
+ - lib/kiosk/server/agent_login.rb
246
+ - lib/kiosk/server/agent_registration.rb
247
+ - lib/kiosk/server/argument_decoder.rb
248
+ - lib/kiosk/server/audit_sink.rb
249
+ - lib/kiosk/server/auth_challenge.rb
250
+ - lib/kiosk/server/auth_challenge_stores.rb
251
+ - lib/kiosk/server/auth_toll.rb
252
+ - lib/kiosk/server/binding_module_gate.rb
253
+ - lib/kiosk/server/caller_timezone.rb
254
+ - lib/kiosk/server/column_spending_cap.rb
255
+ - lib/kiosk/server/configuration_extension.rb
256
+ - lib/kiosk/server/controller_verb.rb
257
+ - lib/kiosk/server/current_request.rb
258
+ - lib/kiosk/server/cursor.rb
259
+ - lib/kiosk/server/device_authorization.rb
260
+ - lib/kiosk/server/device_authorization_stores.rb
261
+ - lib/kiosk/server/device_code_grant.rb
262
+ - lib/kiosk/server/device_verification.rb
263
+ - lib/kiosk/server/engine.rb
264
+ - lib/kiosk/server/errors.rb
265
+ - lib/kiosk/server/event_stores.rb
266
+ - lib/kiosk/server/events.rb
267
+ - lib/kiosk/server/events_cable.rb
268
+ - lib/kiosk/server/events_connection.rb
269
+ - lib/kiosk/server/executor.rb
270
+ - lib/kiosk/server/executor/repeat.rb
271
+ - lib/kiosk/server/executor/spending_cap.rb
272
+ - lib/kiosk/server/failure_log.rb
273
+ - lib/kiosk/server/handler_mixin.rb
274
+ - lib/kiosk/server/handler_registrations.rb
275
+ - lib/kiosk/server/handler_serving.rb
276
+ - lib/kiosk/server/headers.rb
277
+ - lib/kiosk/server/headers_middleware.rb
278
+ - lib/kiosk/server/identity_resolution.rb
279
+ - lib/kiosk/server/issuer_middleware.rb
280
+ - lib/kiosk/server/jwks.rb
281
+ - lib/kiosk/server/jwt_issuer.rb
282
+ - lib/kiosk/server/kyc.rb
283
+ - lib/kiosk/server/kyc_verifier.rb
284
+ - lib/kiosk/server/link_code.rb
285
+ - lib/kiosk/server/linked_assistants.rb
286
+ - lib/kiosk/server/mandate_verifier.rb
287
+ - lib/kiosk/server/open_api.rb
288
+ - lib/kiosk/server/page.rb
289
+ - lib/kiosk/server/payment_claim.rb
290
+ - lib/kiosk/server/payment_setup.rb
291
+ - lib/kiosk/server/pop_verifier.rb
292
+ - lib/kiosk/server/pow_gate.rb
293
+ - lib/kiosk/server/pow_spent_stores.rb
294
+ - lib/kiosk/server/pow_toll.rb
295
+ - lib/kiosk/server/queries.rb
296
+ - lib/kiosk/server/reputation_factors.rb
297
+ - lib/kiosk/server/request_validation.rb
298
+ - lib/kiosk/server/response_validation.rb
299
+ - lib/kiosk/server/result.rb
300
+ - lib/kiosk/server/revocation_stores.rb
301
+ - lib/kiosk/server/routing.rb
302
+ - lib/kiosk/server/schema_definitions.rb
303
+ - lib/kiosk/server/schema_document.rb
304
+ - lib/kiosk/server/schema_slots.rb
305
+ - lib/kiosk/server/schemas/auth.schema.json
306
+ - lib/kiosk/server/schemas/binding.schema.json
307
+ - lib/kiosk/server/schemas/kyc.schema.json
308
+ - lib/kiosk/server/schemas/mandates.schema.json
309
+ - lib/kiosk/server/schemas/pow.schema.json
310
+ - lib/kiosk/server/session_context.rb
311
+ - lib/kiosk/server/settled_spend.rb
312
+ - lib/kiosk/server/signing_key.rb
313
+ - lib/kiosk/server/verb_registry.rb
314
+ - lib/kiosk/server/verb_vocabulary.rb
315
+ - lib/kiosk/server/verb_wire.rb
316
+ - lib/kiosk/server/version.rb
317
+ - lib/kiosk/server/well_known.rb
318
+ - lib/kiosk/server/wire_rendering.rb
319
+ - lib/kiosk/server/wrong_door.rb
320
+ - lib/kiosk/skill_link.rb
321
+ - listen.py
322
+ - requirements.txt
323
+ homepage: https://kiosk.tech
324
+ licenses:
325
+ - Apache-2.0
326
+ metadata:
327
+ homepage_uri: https://kiosk.tech
328
+ source_code_uri: https://github.com/kiosk-hq/kiosk
329
+ changelog_uri: https://github.com/kiosk-hq/kiosk/blob/main/kiosk-server/CHANGELOG.md
330
+ bug_tracker_uri: https://github.com/kiosk-hq/kiosk/issues
331
+ rubygems_mfa_required: 'true'
332
+ rdoc_options: []
333
+ require_paths:
334
+ - lib
335
+ required_ruby_version: !ruby/object:Gem::Requirement
336
+ requirements:
337
+ - - ">="
338
+ - !ruby/object:Gem::Version
339
+ version: '4.0'
340
+ required_rubygems_version: !ruby/object:Gem::Requirement
341
+ requirements:
342
+ - - ">="
343
+ - !ruby/object:Gem::Version
344
+ version: '0'
345
+ requirements: []
346
+ rubygems_version: 4.0.3
347
+ specification_version: 4
348
+ summary: Rails engine + Rack middleware + pure-Ruby helpers for the Kiosk framework
349
+ test_files: []