@digitalpaws/starr 0.0.1

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 (290) hide show
  1. package/README.rst +75 -0
  2. package/data/.nfs.811bbb0d.43c34.4 +0 -0
  3. package/data/.nfs.81ba4cd0.ffff87804.4 +0 -0
  4. package/data/.nfs.82d127f7.fffff5704.4 +0 -0
  5. package/data/.nfs.82d127fe.fffff5704.4 +0 -0
  6. package/data/.nfs.82d159a5.fffff5aa4.4 +0 -0
  7. package/data/.nfs.82d159aa.fffff5aa4.4 +0 -0
  8. package/data/.nfs.82d15a9c.fffff5bb4.4 +0 -0
  9. package/data/.nfs.82d15aa1.fffff5bb4.4 +0 -0
  10. package/data/.nfs.82d15c65.fffff5c24.4 +0 -0
  11. package/data/.nfs.82d1852c.fffff5e24.4 +0 -0
  12. package/data/.nfs.82d18536.fffff5e24.4 +0 -0
  13. package/data/.nfs.82d18dbe.fffff5e44.4 +0 -0
  14. package/data/.nfs.82d18dc6.fffff5e44.4 +0 -0
  15. package/data/.nfs.8309a3f5.fffff82f4.4 +0 -0
  16. package/data/.nfs.8309a3fe.fffff82f4.4 +0 -0
  17. package/data/.nfs.8314122e.fffffb044.4 +0 -0
  18. package/data/.nfs.83141236.fffffb044.4 +0 -0
  19. package/data/.nfs.833c4fe9.fffffbc34.4 +0 -0
  20. package/data/.nfs.833c4ff3.fffffbc34.4 +0 -0
  21. package/data/logs/starr.log +66244 -0
  22. package/data/starr.db +0 -0
  23. package/data/starr.db-shm +0 -0
  24. package/data/starr.db-wal +0 -0
  25. package/data/starr.jwt +1 -0
  26. package/data/starr.key +1 -0
  27. package/dist/auth/auth-service.d.ts +42 -0
  28. package/dist/auth/auth-service.d.ts.map +1 -0
  29. package/dist/auth/auth-service.js +226 -0
  30. package/dist/auth/auth-service.js.map +1 -0
  31. package/dist/auth/http-server.d.ts +16 -0
  32. package/dist/auth/http-server.d.ts.map +1 -0
  33. package/dist/auth/http-server.js +207 -0
  34. package/dist/auth/http-server.js.map +1 -0
  35. package/dist/auth/jwt-secret.d.ts +6 -0
  36. package/dist/auth/jwt-secret.d.ts.map +1 -0
  37. package/dist/auth/jwt-secret.js +51 -0
  38. package/dist/auth/jwt-secret.js.map +1 -0
  39. package/dist/auth/oidc/oidc-flow.d.ts +60 -0
  40. package/dist/auth/oidc/oidc-flow.d.ts.map +1 -0
  41. package/dist/auth/oidc/oidc-flow.js +201 -0
  42. package/dist/auth/oidc/oidc-flow.js.map +1 -0
  43. package/dist/auth/oidc/oidc-provider-service.d.ts +59 -0
  44. package/dist/auth/oidc/oidc-provider-service.d.ts.map +1 -0
  45. package/dist/auth/oidc/oidc-provider-service.js +124 -0
  46. package/dist/auth/oidc/oidc-provider-service.js.map +1 -0
  47. package/dist/auth/oidc/user-service.d.ts +67 -0
  48. package/dist/auth/oidc/user-service.d.ts.map +1 -0
  49. package/dist/auth/oidc/user-service.js +177 -0
  50. package/dist/auth/oidc/user-service.js.map +1 -0
  51. package/dist/auth/rate-limiter.d.ts +31 -0
  52. package/dist/auth/rate-limiter.d.ts.map +1 -0
  53. package/dist/auth/rate-limiter.js +70 -0
  54. package/dist/auth/rate-limiter.js.map +1 -0
  55. package/dist/config/config-service.d.ts +83 -0
  56. package/dist/config/config-service.d.ts.map +1 -0
  57. package/dist/config/config-service.js +309 -0
  58. package/dist/config/config-service.js.map +1 -0
  59. package/dist/config/validate.d.ts +12 -0
  60. package/dist/config/validate.d.ts.map +1 -0
  61. package/dist/config/validate.js +140 -0
  62. package/dist/config/validate.js.map +1 -0
  63. package/dist/content-types/registry.d.ts +75 -0
  64. package/dist/content-types/registry.d.ts.map +1 -0
  65. package/dist/content-types/registry.js +171 -0
  66. package/dist/content-types/registry.js.map +1 -0
  67. package/dist/datastore/db.d.ts +9 -0
  68. package/dist/datastore/db.d.ts.map +1 -0
  69. package/dist/datastore/db.js +27 -0
  70. package/dist/datastore/db.js.map +1 -0
  71. package/dist/datastore/encrypt.d.ts +9 -0
  72. package/dist/datastore/encrypt.d.ts.map +1 -0
  73. package/dist/datastore/encrypt.js +84 -0
  74. package/dist/datastore/encrypt.js.map +1 -0
  75. package/dist/datastore/migrations.d.ts +10 -0
  76. package/dist/datastore/migrations.d.ts.map +1 -0
  77. package/dist/datastore/migrations.js +340 -0
  78. package/dist/datastore/migrations.js.map +1 -0
  79. package/dist/datastore/storage.d.ts +4 -0
  80. package/dist/datastore/storage.d.ts.map +1 -0
  81. package/dist/datastore/storage.js +60 -0
  82. package/dist/datastore/storage.js.map +1 -0
  83. package/dist/events/event-bus.d.ts +15 -0
  84. package/dist/events/event-bus.d.ts.map +1 -0
  85. package/dist/events/event-bus.js +140 -0
  86. package/dist/events/event-bus.js.map +1 -0
  87. package/dist/events/spine.d.ts +31 -0
  88. package/dist/events/spine.d.ts.map +1 -0
  89. package/dist/events/spine.js +68 -0
  90. package/dist/events/spine.js.map +1 -0
  91. package/dist/events/trace.d.ts +24 -0
  92. package/dist/events/trace.d.ts.map +1 -0
  93. package/dist/events/trace.js +33 -0
  94. package/dist/events/trace.js.map +1 -0
  95. package/dist/host.d.ts +65 -0
  96. package/dist/host.d.ts.map +1 -0
  97. package/dist/host.js +94 -0
  98. package/dist/host.js.map +1 -0
  99. package/dist/library/importer.d.ts +29 -0
  100. package/dist/library/importer.d.ts.map +1 -0
  101. package/dist/library/importer.js +145 -0
  102. package/dist/library/importer.js.map +1 -0
  103. package/dist/library/library-cache.d.ts +46 -0
  104. package/dist/library/library-cache.d.ts.map +1 -0
  105. package/dist/library/library-cache.js +152 -0
  106. package/dist/library/library-cache.js.map +1 -0
  107. package/dist/library/library-config.d.ts +12 -0
  108. package/dist/library/library-config.d.ts.map +1 -0
  109. package/dist/library/library-config.js +10 -0
  110. package/dist/library/library-config.js.map +1 -0
  111. package/dist/library/library-scanner.d.ts +62 -0
  112. package/dist/library/library-scanner.d.ts.map +1 -0
  113. package/dist/library/library-scanner.js +336 -0
  114. package/dist/library/library-scanner.js.map +1 -0
  115. package/dist/library/library-service.d.ts +65 -0
  116. package/dist/library/library-service.d.ts.map +1 -0
  117. package/dist/library/library-service.js +197 -0
  118. package/dist/library/library-service.js.map +1 -0
  119. package/dist/library/metadata-matcher.d.ts +56 -0
  120. package/dist/library/metadata-matcher.d.ts.map +1 -0
  121. package/dist/library/metadata-matcher.js +207 -0
  122. package/dist/library/metadata-matcher.js.map +1 -0
  123. package/dist/library/naming.d.ts +8 -0
  124. package/dist/library/naming.d.ts.map +1 -0
  125. package/dist/library/naming.js +47 -0
  126. package/dist/library/naming.js.map +1 -0
  127. package/dist/library/scan-controller.d.ts +95 -0
  128. package/dist/library/scan-controller.d.ts.map +1 -0
  129. package/dist/library/scan-controller.js +379 -0
  130. package/dist/library/scan-controller.js.map +1 -0
  131. package/dist/library/source-resolver.d.ts +17 -0
  132. package/dist/library/source-resolver.d.ts.map +1 -0
  133. package/dist/library/source-resolver.js +75 -0
  134. package/dist/library/source-resolver.js.map +1 -0
  135. package/dist/logging/logger.d.ts +3 -0
  136. package/dist/logging/logger.d.ts.map +1 -0
  137. package/dist/logging/logger.js +107 -0
  138. package/dist/logging/logger.js.map +1 -0
  139. package/dist/main.d.ts +36 -0
  140. package/dist/main.d.ts.map +1 -0
  141. package/dist/main.js +229 -0
  142. package/dist/main.js.map +1 -0
  143. package/dist/plugins/context.d.ts +10 -0
  144. package/dist/plugins/context.d.ts.map +1 -0
  145. package/dist/plugins/context.js +110 -0
  146. package/dist/plugins/context.js.map +1 -0
  147. package/dist/plugins/discovery.d.ts +2 -0
  148. package/dist/plugins/discovery.d.ts.map +1 -0
  149. package/dist/plugins/discovery.js +32 -0
  150. package/dist/plugins/discovery.js.map +1 -0
  151. package/dist/plugins/loader.d.ts +9 -0
  152. package/dist/plugins/loader.d.ts.map +1 -0
  153. package/dist/plugins/loader.js +245 -0
  154. package/dist/plugins/loader.js.map +1 -0
  155. package/dist/state/request-intake.d.ts +26 -0
  156. package/dist/state/request-intake.d.ts.map +1 -0
  157. package/dist/state/request-intake.js +74 -0
  158. package/dist/state/request-intake.js.map +1 -0
  159. package/dist/state/state-store.d.ts +146 -0
  160. package/dist/state/state-store.d.ts.map +1 -0
  161. package/dist/state/state-store.js +465 -0
  162. package/dist/state/state-store.js.map +1 -0
  163. package/dist/state/trace-store.d.ts +12 -0
  164. package/dist/state/trace-store.d.ts.map +1 -0
  165. package/dist/state/trace-store.js +24 -0
  166. package/dist/state/trace-store.js.map +1 -0
  167. package/dist/types/plugin.d.ts +93 -0
  168. package/dist/types/plugin.d.ts.map +1 -0
  169. package/dist/types/plugin.js +4 -0
  170. package/dist/types/plugin.js.map +1 -0
  171. package/dist/web/index.d.ts +10 -0
  172. package/dist/web/index.d.ts.map +1 -0
  173. package/dist/web/index.js +153 -0
  174. package/dist/web/index.js.map +1 -0
  175. package/dist/web/routes/activity.d.ts +6 -0
  176. package/dist/web/routes/activity.d.ts.map +1 -0
  177. package/dist/web/routes/activity.js +31 -0
  178. package/dist/web/routes/activity.js.map +1 -0
  179. package/dist/web/routes/auth.d.ts +6 -0
  180. package/dist/web/routes/auth.d.ts.map +1 -0
  181. package/dist/web/routes/auth.js +142 -0
  182. package/dist/web/routes/auth.js.map +1 -0
  183. package/dist/web/routes/config.d.ts +7 -0
  184. package/dist/web/routes/config.d.ts.map +1 -0
  185. package/dist/web/routes/config.js +204 -0
  186. package/dist/web/routes/config.js.map +1 -0
  187. package/dist/web/routes/content-types.d.ts +6 -0
  188. package/dist/web/routes/content-types.d.ts.map +1 -0
  189. package/dist/web/routes/content-types.js +29 -0
  190. package/dist/web/routes/content-types.js.map +1 -0
  191. package/dist/web/routes/discovery.d.ts +6 -0
  192. package/dist/web/routes/discovery.d.ts.map +1 -0
  193. package/dist/web/routes/discovery.js +111 -0
  194. package/dist/web/routes/discovery.js.map +1 -0
  195. package/dist/web/routes/library-import.d.ts +6 -0
  196. package/dist/web/routes/library-import.d.ts.map +1 -0
  197. package/dist/web/routes/library-import.js +120 -0
  198. package/dist/web/routes/library-import.js.map +1 -0
  199. package/dist/web/routes/library-management.d.ts +6 -0
  200. package/dist/web/routes/library-management.d.ts.map +1 -0
  201. package/dist/web/routes/library-management.js +120 -0
  202. package/dist/web/routes/library-management.js.map +1 -0
  203. package/dist/web/routes/library.d.ts +6 -0
  204. package/dist/web/routes/library.d.ts.map +1 -0
  205. package/dist/web/routes/library.js +28 -0
  206. package/dist/web/routes/library.js.map +1 -0
  207. package/dist/web/routes/oidc.d.ts +9 -0
  208. package/dist/web/routes/oidc.d.ts.map +1 -0
  209. package/dist/web/routes/oidc.js +203 -0
  210. package/dist/web/routes/oidc.js.map +1 -0
  211. package/dist/web/routes/requests.d.ts +6 -0
  212. package/dist/web/routes/requests.d.ts.map +1 -0
  213. package/dist/web/routes/requests.js +183 -0
  214. package/dist/web/routes/requests.js.map +1 -0
  215. package/dist/web/routes/sse.d.ts +6 -0
  216. package/dist/web/routes/sse.d.ts.map +1 -0
  217. package/dist/web/routes/sse.js +54 -0
  218. package/dist/web/routes/sse.js.map +1 -0
  219. package/package.json +33 -0
  220. package/package.json.license +2 -0
  221. package/src/auth/auth-service.ts +333 -0
  222. package/src/auth/http-server.ts +249 -0
  223. package/src/auth/jwt-secret.ts +65 -0
  224. package/src/auth/oidc/oidc-flow.ts +266 -0
  225. package/src/auth/oidc/oidc-provider-service.ts +174 -0
  226. package/src/auth/oidc/user-service.ts +227 -0
  227. package/src/auth/rate-limiter.ts +85 -0
  228. package/src/config/config-service.ts +434 -0
  229. package/src/config/validate.ts +153 -0
  230. package/src/content-types/registry.ts +194 -0
  231. package/src/datastore/db.ts +38 -0
  232. package/src/datastore/encrypt.ts +107 -0
  233. package/src/datastore/migrations.ts +367 -0
  234. package/src/datastore/storage.ts +83 -0
  235. package/src/events/event-bus.ts +180 -0
  236. package/src/events/spine.ts +87 -0
  237. package/src/events/trace.ts +38 -0
  238. package/src/host.ts +130 -0
  239. package/src/library/importer.ts +174 -0
  240. package/src/library/library-cache.ts +212 -0
  241. package/src/library/library-config.ts +22 -0
  242. package/src/library/library-scanner.ts +404 -0
  243. package/src/library/library-service.ts +282 -0
  244. package/src/library/metadata-matcher.ts +285 -0
  245. package/src/library/naming.ts +59 -0
  246. package/src/library/scan-controller.ts +490 -0
  247. package/src/library/source-resolver.ts +92 -0
  248. package/src/logging/logger.ts +115 -0
  249. package/src/main.ts +364 -0
  250. package/src/plugins/context.ts +138 -0
  251. package/src/plugins/discovery.ts +29 -0
  252. package/src/plugins/loader.ts +309 -0
  253. package/src/state/request-intake.ts +101 -0
  254. package/src/state/state-store.ts +621 -0
  255. package/src/state/trace-store.ts +27 -0
  256. package/src/types/plugin.ts +110 -0
  257. package/src/web/index.ts +182 -0
  258. package/src/web/routes/activity.ts +41 -0
  259. package/src/web/routes/auth.ts +170 -0
  260. package/src/web/routes/config.ts +282 -0
  261. package/src/web/routes/content-types.ts +42 -0
  262. package/src/web/routes/discovery.ts +156 -0
  263. package/src/web/routes/library-import.ts +196 -0
  264. package/src/web/routes/library-management.ts +140 -0
  265. package/src/web/routes/library.ts +46 -0
  266. package/src/web/routes/oidc.ts +260 -0
  267. package/src/web/routes/requests.ts +250 -0
  268. package/src/web/routes/sse.ts +92 -0
  269. package/tests/auth.test.ts +510 -0
  270. package/tests/config-route.test.ts +345 -0
  271. package/tests/config.test.ts +612 -0
  272. package/tests/content-types.test.ts +376 -0
  273. package/tests/datastore.test.ts +345 -0
  274. package/tests/e2e.test.ts +430 -0
  275. package/tests/event-bus.test.ts +925 -0
  276. package/tests/host.test.ts +449 -0
  277. package/tests/library-cache.test.ts +171 -0
  278. package/tests/library-scanner.test.ts +177 -0
  279. package/tests/library.test.ts +210 -0
  280. package/tests/loader-context.test.ts +644 -0
  281. package/tests/logger-jsonl.test.ts +154 -0
  282. package/tests/metadata-matcher.test.ts +198 -0
  283. package/tests/oidc.test.ts +218 -0
  284. package/tests/scan-controller.test.ts +328 -0
  285. package/tests/source-resolver.test.ts +100 -0
  286. package/tests/starr-video-integration.test.ts +153 -0
  287. package/tests/state-store.test.ts +700 -0
  288. package/tests/trace-history.test.ts +356 -0
  289. package/tsconfig.json +8 -0
  290. package/tsconfig.json.license +2 -0
@@ -0,0 +1,177 @@
1
+ // SPDX-License-Identifier: 0BSD
2
+ // SPDX-FileCopyrightText: 2025 Digi <digitalpaws@proton.me>
3
+ import { randomUUID } from "node:crypto";
4
+ export class UserService {
5
+ db;
6
+ logger;
7
+ constructor(db, logger) {
8
+ this.db = db;
9
+ this.logger = logger;
10
+ }
11
+ /** Get a user by UUID or the fixed admin id. */
12
+ get(id) {
13
+ const row = this.db
14
+ .prepare("SELECT * FROM users WHERE id = @id")
15
+ .get({ id });
16
+ return row ? this.rowToUser(row) : null;
17
+ }
18
+ /** Get a user by username. */
19
+ getByUsername(username) {
20
+ const row = this.db
21
+ .prepare("SELECT * FROM users WHERE username = @username")
22
+ .get({ username });
23
+ return row ? this.rowToUser(row) : null;
24
+ }
25
+ /**
26
+ * Find a user by OIDC subject and provider.
27
+ * This is the primary lookup during OIDC callback.
28
+ */
29
+ getByOidcSub(oidcSub, oidcProviderId) {
30
+ const row = this.db
31
+ .prepare("SELECT * FROM users WHERE oidc_sub = @sub AND oidc_provider_id = @providerId")
32
+ .get({ sub: oidcSub, providerId: oidcProviderId });
33
+ return row ? this.rowToUser(row) : null;
34
+ }
35
+ /**
36
+ * Find or create a user from OIDC claims during callback.
37
+ *
38
+ * Steps:
39
+ * 1. Look up by (oidc_sub, oidc_provider_id).
40
+ * 2. If found, update display_name, avatar_url, username from claims.
41
+ * 3. If not found, create a new user with provider='oidc'.
42
+ *
43
+ * Returns the user and a boolean indicating whether it was newly created.
44
+ */
45
+ findOrCreateFromOidc(claims, oidcProviderId, defaultRole) {
46
+ // 1. Look up existing user by OIDC identity
47
+ let user = this.getByOidcSub(claims.sub, oidcProviderId);
48
+ if (user) {
49
+ // 2. Update claims (username/display name/avatar may have changed at the IdP)
50
+ const displayName = claims.name ?? claims.preferred_username ?? claims.sub;
51
+ const avatarUrl = claims.picture ?? null;
52
+ const username = claims.preferred_username ?? claims.sub;
53
+ this.db.prepare(`
54
+ UPDATE users SET
55
+ username = @username,
56
+ display_name = @displayName,
57
+ avatar_url = @avatarUrl,
58
+ updated_at = datetime('now')
59
+ WHERE id = @id
60
+ `).run({
61
+ id: user.id,
62
+ username,
63
+ displayName,
64
+ avatarUrl,
65
+ });
66
+ user = this.get(user.id);
67
+ return { user, created: false };
68
+ }
69
+ // 3. Create new user
70
+ const id = randomUUID();
71
+ const displayName = claims.name ?? claims.preferred_username ?? claims.sub;
72
+ const avatarUrl = claims.picture ?? null;
73
+ const username = claims.preferred_username ?? claims.sub;
74
+ // If the preferred_username is already taken, append a suffix
75
+ let finalUsername = username;
76
+ let suffix = 1;
77
+ while (this.getByUsername(finalUsername)) {
78
+ finalUsername = `${username}_${suffix}`;
79
+ suffix++;
80
+ }
81
+ this.db.prepare(`
82
+ INSERT INTO users (id, username, display_name, avatar_url, role, provider,
83
+ oidc_sub, oidc_provider_id)
84
+ VALUES (@id, @username, @displayName, @avatarUrl, @role, 'oidc',
85
+ @oidcSub, @oidcProviderId)
86
+ `).run({
87
+ id,
88
+ username: finalUsername,
89
+ displayName,
90
+ avatarUrl,
91
+ role: defaultRole,
92
+ oidcSub: claims.sub,
93
+ oidcProviderId,
94
+ });
95
+ user = this.get(id);
96
+ this.logger.info("OIDC user auto-created", {
97
+ userId: user.id,
98
+ username: user.username,
99
+ providerId: oidcProviderId,
100
+ });
101
+ return { user, created: true };
102
+ }
103
+ /** List all users (admin only). */
104
+ list() {
105
+ const rows = this.db
106
+ .prepare("SELECT * FROM users ORDER BY created_at ASC")
107
+ .all();
108
+ return rows.map(this.rowToUser);
109
+ }
110
+ /** Count how many admin users exist. */
111
+ countAdmins() {
112
+ const row = this.db
113
+ .prepare("SELECT COUNT(*) AS count FROM users WHERE role = 'admin'")
114
+ .get();
115
+ return row.count;
116
+ }
117
+ /** Change a user's role. Returns the updated user or null if not found. */
118
+ setRole(id, role) {
119
+ const user = this.get(id);
120
+ if (!user)
121
+ return null;
122
+ // Prevent demoting the built-in local admin account
123
+ if (id === "admin" && role === "user") {
124
+ throw new Error("Cannot demote the built-in admin account");
125
+ }
126
+ // Prevent demoting the last admin
127
+ if (user.role === "admin" && role === "user") {
128
+ const adminCount = this.countAdmins();
129
+ if (adminCount <= 1) {
130
+ throw new Error("Cannot demote the last admin user");
131
+ }
132
+ }
133
+ this.db.prepare(`
134
+ UPDATE users SET role = @role, updated_at = datetime('now') WHERE id = @id
135
+ `).run({ id, role });
136
+ this.logger.info("user role changed", {
137
+ targetUserId: id,
138
+ newRole: role,
139
+ });
140
+ return this.get(id);
141
+ }
142
+ /** Check if there is at least one admin user. */
143
+ hasAdmin() {
144
+ const row = this.db
145
+ .prepare("SELECT 1 FROM users WHERE role = 'admin' LIMIT 1")
146
+ .get();
147
+ return row !== undefined;
148
+ }
149
+ /**
150
+ * Resolve a user identifier (UUID or "admin") to a user.
151
+ * Used when validating sessions that may have either format in user_id.
152
+ */
153
+ resolveUser(userId) {
154
+ // Try direct lookup by id first
155
+ const user = this.get(userId);
156
+ if (user)
157
+ return user;
158
+ // Fallback: try as username (for backward compat with old sessions)
159
+ return this.getByUsername(userId);
160
+ }
161
+ // ── Private helpers ──
162
+ rowToUser(row) {
163
+ return {
164
+ id: row.id,
165
+ username: row.username,
166
+ displayName: row.display_name,
167
+ avatarUrl: row.avatar_url,
168
+ role: row.role,
169
+ provider: row.provider,
170
+ oidcSub: row.oidc_sub,
171
+ oidcProviderId: row.oidc_provider_id,
172
+ createdAt: row.created_at,
173
+ updatedAt: row.updated_at,
174
+ };
175
+ }
176
+ }
177
+ //# sourceMappingURL=user-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-service.js","sourceRoot":"","sources":["../../../src/auth/oidc/user-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { FastifyRequest, FastifyReply } from "fastify";
2
+ export declare class RateLimiter {
3
+ private map;
4
+ private maxAttempts;
5
+ private windowMs;
6
+ constructor(maxAttempts?: number, windowMinutes?: number);
7
+ /**
8
+ * Record a failed attempt for the given key (typically IP).
9
+ * Returns true if the attempt is allowed, false if rate-limited.
10
+ */
11
+ check(key: string): boolean;
12
+ /**
13
+ * Reset the rate limit for a key (called on successful login).
14
+ */
15
+ reset(key: string): void;
16
+ /**
17
+ * How many seconds until the window resets for a key.
18
+ * Used to inform the client.
19
+ */
20
+ retryAfterSeconds(key: string): number;
21
+ }
22
+ /**
23
+ * Return a Fastify preHandler hook that rate-limits by IP.
24
+ * Usage:
25
+ * server.post("/api/auth/login", { preHandler: rateLimit(5, 60) }, handler)
26
+ *
27
+ * @param maxAttempts Maximum attempts allowed in the window.
28
+ * @param windowMinutes Time window in minutes.
29
+ */
30
+ export declare function rateLimit(maxAttempts: number, windowMinutes: number): (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
31
+ //# sourceMappingURL=rate-limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/auth/rate-limiter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAO5D,qBAAa,WAAW;IACtB,OAAO,CAAC,GAAG,CAAqC;IAChD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;gBAEb,WAAW,SAAI,EAAE,aAAa,SAAK;IAK/C;;;OAGG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAiB3B;;OAEG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIxB;;;OAGG;IACH,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;CAMvC;AAID;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,IAGpD,SAAS,cAAc,EAAE,OAAO,YAAY,mBAW3D"}
@@ -0,0 +1,70 @@
1
+ // SPDX-License-Identifier: 0BSD
2
+ // SPDX-FileCopyrightText: 2025 Digi <digitalpaws@proton.me>
3
+ export class RateLimiter {
4
+ map = new Map();
5
+ maxAttempts;
6
+ windowMs;
7
+ constructor(maxAttempts = 4, windowMinutes = 15) {
8
+ this.maxAttempts = maxAttempts;
9
+ this.windowMs = windowMinutes * 60_000;
10
+ }
11
+ /**
12
+ * Record a failed attempt for the given key (typically IP).
13
+ * Returns true if the attempt is allowed, false if rate-limited.
14
+ */
15
+ check(key) {
16
+ const now = Date.now();
17
+ const entry = this.map.get(key);
18
+ if (!entry || now - entry.windowStart > this.windowMs) {
19
+ // New window
20
+ this.map.set(key, { count: 1, windowStart: now });
21
+ return true;
22
+ }
23
+ entry.count++;
24
+ if (entry.count > this.maxAttempts) {
25
+ return false; // rate-limited
26
+ }
27
+ return true;
28
+ }
29
+ /**
30
+ * Reset the rate limit for a key (called on successful login).
31
+ */
32
+ reset(key) {
33
+ this.map.delete(key);
34
+ }
35
+ /**
36
+ * How many seconds until the window resets for a key.
37
+ * Used to inform the client.
38
+ */
39
+ retryAfterSeconds(key) {
40
+ const entry = this.map.get(key);
41
+ if (!entry)
42
+ return 0;
43
+ const elapsed = Date.now() - entry.windowStart;
44
+ return Math.max(0, Math.ceil((this.windowMs - elapsed) / 1000));
45
+ }
46
+ }
47
+ // ── Fastify preHandler wrapper ────────────────────────────────
48
+ /**
49
+ * Return a Fastify preHandler hook that rate-limits by IP.
50
+ * Usage:
51
+ * server.post("/api/auth/login", { preHandler: rateLimit(5, 60) }, handler)
52
+ *
53
+ * @param maxAttempts Maximum attempts allowed in the window.
54
+ * @param windowMinutes Time window in minutes.
55
+ */
56
+ export function rateLimit(maxAttempts, windowMinutes) {
57
+ const limiter = new RateLimiter(maxAttempts, windowMinutes);
58
+ return async (request, reply) => {
59
+ const key = request.ip;
60
+ const allowed = limiter.check(key);
61
+ if (!allowed) {
62
+ reply
63
+ .status(429)
64
+ .header("Retry-After", String(limiter.retryAfterSeconds(key)))
65
+ .send({ error: "Too many requests. Please try again later." });
66
+ return;
67
+ }
68
+ };
69
+ }
70
+ //# sourceMappingURL=rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/auth/rate-limiter.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,4DAA4D;AAS5D,MAAM,OAAO,WAAW;IACd,GAAG,GAAG,IAAI,GAAG,EAA0B,CAAC;IACxC,WAAW,CAAS;IACpB,QAAQ,CAAS;IAEzB,YAAY,WAAW,GAAG,CAAC,EAAE,aAAa,GAAG,EAAE;QAC7C,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,aAAa,GAAG,MAAM,CAAC;IACzC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAW;QACf,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEhC,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACtD,aAAa;YACb,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;YAClD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,IAAI,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC,CAAC,eAAe;QAC/B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAW;QACf,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAED;;;OAGG;IACH,iBAAiB,CAAC,GAAW;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,CAAC;QACrB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,WAAW,CAAC;QAC/C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IAClE,CAAC;CACF;AAED,iEAAiE;AAEjE;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,WAAmB,EAAE,aAAqB;IAClE,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAE5D,OAAO,KAAK,EAAE,OAAuB,EAAE,KAAmB,EAAE,EAAE;QAC5D,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,KAAK;iBACF,MAAM,CAAC,GAAG,CAAC;iBACX,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC;iBAC7D,IAAI,CAAC,EAAE,KAAK,EAAE,4CAA4C,EAAE,CAAC,CAAC;YACjE,OAAO;QACT,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,83 @@
1
+ import type Database from "better-sqlite3";
2
+ import type { ConfigSchema, Logger } from "../types/plugin.js";
3
+ import { type ValidationResult } from "./validate.js";
4
+ /**
5
+ * Sentinel value used to mask secret fields in UI-exported data.
6
+ * When update() receives this value for a secret field, it preserves
7
+ * the existing encrypted value rather than overwriting it.
8
+ */
9
+ export declare const SECRET_UNCHANGED_SENTINEL = "__STARR_SECRET_UNCHANGED__";
10
+ export interface PluginConfigEntry {
11
+ schema: ConfigSchema<any>;
12
+ values: Record<string, unknown>;
13
+ needsConfiguration: boolean;
14
+ updatedAt: string;
15
+ }
16
+ export interface PluginConfigSummary {
17
+ pluginId: string;
18
+ instanceId?: string;
19
+ needsConfiguration: boolean;
20
+ updatedAt: string;
21
+ /** The connected library ID, if any (for downloader instances). */
22
+ libraryId?: string;
23
+ }
24
+ export declare class ConfigService {
25
+ private db;
26
+ private logger;
27
+ private onReload?;
28
+ private getStmt;
29
+ private getByInstanceStmt;
30
+ private upsertStmt;
31
+ private listStmt;
32
+ private listInstancesStmt;
33
+ private deleteInstanceStmt;
34
+ constructor(db: Database.Database, logger: Logger, onReload?: (pluginId: string) => void);
35
+ /**
36
+ * Called by the plugin context during register.
37
+ * Returns read-only validated values.
38
+ */
39
+ register<T>(pluginId: string, schema: ConfigSchema<T>, instanceId?: string): Readonly<T>;
40
+ /**
41
+ * Called by the admin settings API when saving config.
42
+ * Updates values, persists, and triggers reload.
43
+ */
44
+ update(pluginId: string, schema: ConfigSchema<any>, input: Record<string, unknown>, instanceId?: string): ValidationResult;
45
+ /**
46
+ * Called by the admin UI to get render data.
47
+ * Returns schema + values (with secrets masked) + needsConfiguration flag.
48
+ */
49
+ get(pluginId: string, instanceId?: string): PluginConfigEntry | undefined;
50
+ /**
51
+ * Called by the admin UI to list all plugins with config status.
52
+ */
53
+ list(): PluginConfigSummary[];
54
+ /**
55
+ * List all instances for a given plugin.
56
+ */
57
+ listInstances(pluginId: string): PluginConfigSummary[];
58
+ /**
59
+ * Create a new plugin instance with the given instanceId and config values.
60
+ * Validates and persists.
61
+ */
62
+ createInstance<T>(pluginId: string, instanceId: string, schema: ConfigSchema<T>, values: Record<string, unknown>): ValidationResult;
63
+ /**
64
+ * Delete a plugin instance and its config.
65
+ */
66
+ deleteInstance(pluginId: string, instanceId: string): void;
67
+ /**
68
+ * Return decrypted stored values for a plugin, or undefined if no row exists.
69
+ * Used by the test-connection endpoint to resolve secret sentinels.
70
+ */
71
+ getDecryptedValues(pluginId: string, instanceId?: string): Record<string, unknown> | undefined;
72
+ /**
73
+ * Check whether a plugin needs configuration (required fields missing).
74
+ * Used by context.ts for the debug log.
75
+ */
76
+ needsConfiguration(pluginId: string, instanceId?: string): boolean;
77
+ private buildDefaults;
78
+ private computeNeedsConfiguration;
79
+ private encryptValues;
80
+ private decryptValues;
81
+ private maskSecretValues;
82
+ }
83
+ //# sourceMappingURL=config-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-service.d.ts","sourceRoot":"","sources":["../../src/config/config-service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGtE;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,+BAA+B,CAAC;AAEtE,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,CAA6B;IAG9C,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,kBAAkB,CAAqB;gBAG7C,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI;IA+BvC;;;OAGG;IACH,QAAQ,CAAC,CAAC,EACR,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EACvB,UAAU,SAAY,GACrB,QAAQ,CAAC,CAAC,CAAC;IAyDd;;;OAGG;IACH,MAAM,CACJ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,EACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,UAAU,SAAY,GACrB,gBAAgB;IA0CnB;;;OAGG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,SAAY,GAAG,iBAAiB,GAAG,SAAS;IA0B5E;;OAEG;IACH,IAAI,IAAI,mBAAmB,EAAE;IA2B7B;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,EAAE;IA2BtD;;;OAGG;IACH,cAAc,CAAC,CAAC,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,gBAAgB;IAkBnB;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAO1D;;;OAGG;IACH,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,SAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IAYjG;;;OAGG;IACH,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,SAAY,GAAG,OAAO;IAcrE,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,yBAAyB;IAkBjC,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,gBAAgB;CAezB"}