@mug-lab/cookie-auth-proxy 0.1.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.
package/config.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "listenHost": "localhost",
3
+ "listenPort": 4300,
4
+ "clientOrigin": "http://localhost:8080",
5
+ "apiOrigin": "",
6
+ "apiOriginAllowedPatterns": [],
7
+ "adminNotice": "",
8
+ "apiPathPatterns": [
9
+ "^/api(?:/|$)"
10
+ ],
11
+ "apiPathExcludes": [
12
+ "^/$",
13
+ "^/favicon\\.ico$",
14
+ "^/(?:assets|static)(?:/|$)",
15
+ "^/sockjs-node(?:/|$)"
16
+ ],
17
+ "preserveLocationHeaderPatterns": [],
18
+ "locationHeaderQueryOverrides": [],
19
+ "apiCookie": "sessionId=",
20
+ "sensitiveHeaderNames": [
21
+ "authorization",
22
+ "cookie",
23
+ "proxy-authorization",
24
+ "set-cookie",
25
+ "x-api-key",
26
+ "x-auth-token"
27
+ ],
28
+ "sensitiveCookieNames": [],
29
+ "startupStubImportDir": "stubs",
30
+ "startupOverrideImportDir": "overrides",
31
+ "serverAppPath": "/",
32
+ "adminHost": "localhost",
33
+ "adminPort": 4301,
34
+ "historyLimit": 200,
35
+ "maxAdminBodyBytes": 1048576,
36
+ "maxRequestBodyInspectionBytes": 10485760,
37
+ "maxResponseBodyRewriteBytes": 52428800,
38
+ "maxHistoryBodyBytes": 524288,
39
+ "allowRemoteAccess": false,
40
+ "stubsEnabled": false,
41
+ "jsonOverridesEnabled": false,
42
+ "logLevel": "info"
43
+ }
@@ -0,0 +1,43 @@
1
+ {
2
+ "listenHost": "localhost",
3
+ "listenPort": 4300,
4
+ "clientOrigin": "http://localhost:8080",
5
+ "apiOrigin": "https://api.invalid",
6
+ "apiOriginAllowedPatterns": [],
7
+ "adminNotice": "",
8
+ "apiPathPatterns": [
9
+ "^/api(?:/|$)"
10
+ ],
11
+ "apiPathExcludes": [
12
+ "^/$",
13
+ "^/favicon\\.ico$",
14
+ "^/(?:assets|static)(?:/|$)",
15
+ "^/sockjs-node(?:/|$)"
16
+ ],
17
+ "preserveLocationHeaderPatterns": [],
18
+ "locationHeaderQueryOverrides": [],
19
+ "apiCookie": "sessionId=",
20
+ "sensitiveHeaderNames": [
21
+ "authorization",
22
+ "cookie",
23
+ "proxy-authorization",
24
+ "set-cookie",
25
+ "x-api-key",
26
+ "x-auth-token"
27
+ ],
28
+ "sensitiveCookieNames": [],
29
+ "startupStubImportDir": "cookie-auth-proxy/stubs",
30
+ "startupOverrideImportDir": "cookie-auth-proxy/overrides",
31
+ "serverAppPath": "/",
32
+ "adminHost": "localhost",
33
+ "adminPort": 4301,
34
+ "historyLimit": 200,
35
+ "maxAdminBodyBytes": 1048576,
36
+ "maxRequestBodyInspectionBytes": 10485760,
37
+ "maxResponseBodyRewriteBytes": 52428800,
38
+ "maxHistoryBodyBytes": 524288,
39
+ "allowRemoteAccess": false,
40
+ "stubsEnabled": false,
41
+ "jsonOverridesEnabled": false,
42
+ "logLevel": "info"
43
+ }
@@ -0,0 +1,4 @@
1
+ Place exported JSON override files in this directory to load them at proxy startup.
2
+
3
+ Files are loaded in filename order. Use prefixes such as `010-user-role.json`
4
+ when you need predictable override priority.
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@mug-lab/cookie-auth-proxy",
3
+ "version": "0.1.0",
4
+ "description": "Local development proxy for cookie-authenticated web apps.",
5
+ "type": "commonjs",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/mug-lab/cookie-auth-proxy.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/mug-lab/cookie-auth-proxy/issues"
13
+ },
14
+ "homepage": "https://github.com/mug-lab/cookie-auth-proxy#readme",
15
+ "bin": {
16
+ "cookie-auth-proxy": "src/proxy.js"
17
+ },
18
+ "files": [
19
+ "src",
20
+ "README.md",
21
+ "SECURITY.md",
22
+ "config.json",
23
+ "cookie-auth-proxy.config.example.json",
24
+ "stubs/README.md",
25
+ "overrides/README.md"
26
+ ],
27
+ "scripts": {
28
+ "start": "node src/proxy.js --config config.json",
29
+ "start:example": "node src/proxy.js --config cookie-auth-proxy.config.example.json",
30
+ "test": "node test/check-syntax.js && node --test"
31
+ },
32
+ "engines": {
33
+ "node": ">=18"
34
+ }
35
+ }
@@ -0,0 +1,508 @@
1
+ * {
2
+ box-sizing: border-box;
3
+ }
4
+ :root {
5
+ --app-header-height: 46px;
6
+ --admin-notice-height: 0px;
7
+ --right-pane-left: 0px;
8
+ --right-pane-width: 100vw;
9
+ --right-sticky-height: 0px;
10
+ --sticky-top: var(--app-header-height);
11
+ }
12
+ html,
13
+ body {
14
+ min-height: 100%;
15
+ }
16
+ body:has(.admin-notice:not(.hidden)) {
17
+ --admin-notice-height: 40px;
18
+ --sticky-top: calc(var(--app-header-height) + var(--admin-notice-height));
19
+ }
20
+ body {
21
+ margin: 0;
22
+ font-family: Arial, sans-serif;
23
+ color: #1d2733;
24
+ background: #f5f7fa;
25
+ }
26
+ header {
27
+ background: #192433;
28
+ color: #fff;
29
+ padding: 14px 20px;
30
+ position: sticky;
31
+ top: 0;
32
+ z-index: 100;
33
+ }
34
+ .admin-notice {
35
+ background: #fff3d6;
36
+ border-bottom: 1px solid #e8b75c;
37
+ color: #754600;
38
+ font-size: 14px;
39
+ font-weight: 700;
40
+ padding: 10px 20px;
41
+ position: sticky;
42
+ top: var(--app-header-height);
43
+ white-space: pre-wrap;
44
+ z-index: 90;
45
+ }
46
+ main {
47
+ display: grid;
48
+ grid-template-columns: minmax(420px, 460px) 1fr;
49
+ gap: 16px;
50
+ padding: 16px;
51
+ align-items: start;
52
+ }
53
+ main > div {
54
+ max-height: calc(100vh - var(--sticky-top) - 32px);
55
+ overflow: auto;
56
+ padding-right: 4px;
57
+ position: sticky;
58
+ top: calc(var(--sticky-top) + 16px);
59
+ }
60
+ section {
61
+ background: #fff;
62
+ border: 1px solid #d8e0ea;
63
+ border-radius: 8px;
64
+ padding: 16px;
65
+ margin-bottom: 16px;
66
+ }
67
+ .main-panel {
68
+ overflow: visible;
69
+ }
70
+ h1 {
71
+ font-size: 18px;
72
+ margin: 0;
73
+ }
74
+ h2 {
75
+ font-size: 15px;
76
+ margin: 0 0 12px;
77
+ }
78
+ h3 {
79
+ font-size: 13px;
80
+ margin: 12px 0 6px;
81
+ }
82
+ label {
83
+ display: block;
84
+ font-size: 12px;
85
+ font-weight: 700;
86
+ margin: 12px 0 4px;
87
+ }
88
+ input,
89
+ textarea,
90
+ select {
91
+ width: 100%;
92
+ border: 1px solid #b9c5d3;
93
+ border-radius: 6px;
94
+ padding: 8px;
95
+ font: inherit;
96
+ }
97
+ textarea {
98
+ min-height: 96px;
99
+ resize: vertical;
100
+ }
101
+ button {
102
+ border: 1px solid #9fb0c2;
103
+ border-radius: 6px;
104
+ background: #fff;
105
+ cursor: pointer;
106
+ padding: 8px 10px;
107
+ font: inherit;
108
+ transition:
109
+ background 0.12s ease,
110
+ border-color 0.12s ease,
111
+ box-shadow 0.12s ease,
112
+ transform 0.06s ease;
113
+ }
114
+ button:hover:not(:disabled) {
115
+ border-color: #2457d6;
116
+ box-shadow: 0 1px 5px rgba(36, 87, 214, 0.18);
117
+ }
118
+ button:active:not(:disabled) {
119
+ transform: translateY(1px);
120
+ background: #e9efff;
121
+ }
122
+ button.primary {
123
+ background: #2457d6;
124
+ border-color: #2457d6;
125
+ color: #fff;
126
+ }
127
+ button.primary:hover:not(:disabled) {
128
+ background: #1d49b7;
129
+ }
130
+ button.danger {
131
+ background: #fff7f7;
132
+ border-color: #e0a4a4;
133
+ color: #8b1e1e;
134
+ }
135
+ button.danger:hover:not(:disabled) {
136
+ border-color: #c84040;
137
+ color: #9f1d1d;
138
+ box-shadow: 0 1px 5px rgba(200, 64, 64, 0.18);
139
+ }
140
+ button:disabled {
141
+ cursor: not-allowed;
142
+ opacity: 0.45;
143
+ }
144
+ button.flash {
145
+ animation: flash 0.42s ease;
146
+ }
147
+ button.icon {
148
+ flex: 0 0 auto;
149
+ min-width: 34px;
150
+ height: 34px;
151
+ padding: 0 8px;
152
+ line-height: 1;
153
+ }
154
+ .external-link-icon {
155
+ display: inline-block;
156
+ font-size: 12px;
157
+ line-height: 1;
158
+ margin-left: 6px;
159
+ transform: translateY(-1px);
160
+ }
161
+ @keyframes flash {
162
+ 0% {
163
+ box-shadow: 0 0 0 0 rgba(36, 87, 214, 0.5);
164
+ }
165
+ 100% {
166
+ box-shadow: 0 0 0 8px rgba(36, 87, 214, 0);
167
+ }
168
+ }
169
+ .row {
170
+ display: flex;
171
+ gap: 8px;
172
+ align-items: center;
173
+ }
174
+ .row > * {
175
+ flex: 1;
176
+ }
177
+ .muted {
178
+ color: #637083;
179
+ font-size: 12px;
180
+ }
181
+ .tabs {
182
+ display: flex;
183
+ gap: 8px;
184
+ border-bottom: 1px solid #d8e0ea;
185
+ margin: 0 0 12px;
186
+ background: #fff;
187
+ padding: 0 0 8px;
188
+ }
189
+ .tab {
190
+ flex: 0 0 auto;
191
+ transition: none;
192
+ }
193
+ .tab.active {
194
+ background: #192433;
195
+ border-color: #192433;
196
+ color: #fff;
197
+ }
198
+ .panel {
199
+ display: none;
200
+ }
201
+ .panel.active {
202
+ display: block;
203
+ padding-top: var(--right-sticky-height);
204
+ }
205
+ .panel-sticky {
206
+ background: #fff;
207
+ border: 1px solid #d8e0ea;
208
+ border-top: 0;
209
+ border-bottom-color: #eef2f7;
210
+ border-radius: 0 0 8px 8px;
211
+ left: var(--right-pane-left);
212
+ margin: 0;
213
+ padding: 0 16px 12px;
214
+ position: fixed;
215
+ top: calc(var(--sticky-top) - 4px);
216
+ width: var(--right-pane-width);
217
+ z-index: 20;
218
+ box-shadow:
219
+ 0 8px 0 #fff,
220
+ 0 2px 8px rgba(25, 36, 51, 0.08);
221
+ }
222
+ .scroll-area {
223
+ overflow: visible;
224
+ }
225
+ .toolbar {
226
+ display: flex;
227
+ flex-wrap: wrap;
228
+ gap: 8px;
229
+ align-items: center;
230
+ justify-content: space-between;
231
+ margin-bottom: 12px;
232
+ }
233
+ .filters {
234
+ display: flex;
235
+ flex-wrap: wrap;
236
+ gap: 6px;
237
+ }
238
+ .filters button {
239
+ padding: 6px 9px;
240
+ }
241
+ .filters button.active {
242
+ background: #e8eef8;
243
+ border-color: #6c82a0;
244
+ font-weight: 700;
245
+ }
246
+ .history,
247
+ .stubs,
248
+ .overrides {
249
+ display: grid;
250
+ gap: 8px;
251
+ }
252
+ .entry {
253
+ border: 1px solid #d8e0ea;
254
+ border-radius: 6px;
255
+ padding: 10px;
256
+ }
257
+ .filter-summary {
258
+ align-items: center;
259
+ color: #7a8797;
260
+ display: flex;
261
+ font-size: 12px;
262
+ gap: 10px;
263
+ justify-content: center;
264
+ padding: 2px 0;
265
+ }
266
+ .filter-summary::before,
267
+ .filter-summary::after {
268
+ background: #d8e0ea;
269
+ content: "";
270
+ flex: 1;
271
+ height: 1px;
272
+ max-width: 160px;
273
+ }
274
+ .entry summary {
275
+ cursor: pointer;
276
+ font-weight: 700;
277
+ list-style-position: outside;
278
+ margin-left: 18px;
279
+ padding-left: 4px;
280
+ }
281
+ .entry summary .entry-head {
282
+ display: inline-flex;
283
+ width: calc(100% - 4px);
284
+ vertical-align: middle;
285
+ }
286
+ .entry.status-2xx {
287
+ border-color: #98c7ff;
288
+ background: #f2f8ff;
289
+ }
290
+ .entry.status-3xx {
291
+ border-color: #a7d9dd;
292
+ background: #f2fbfc;
293
+ }
294
+ .entry.status-4xx {
295
+ border-color: #f1c28d;
296
+ background: #fff7ed;
297
+ }
298
+ .entry.status-5xx {
299
+ border-color: #f0a0a0;
300
+ background: #fff1f1;
301
+ }
302
+ .entry.disabled-stub {
303
+ filter: grayscale(0.75);
304
+ opacity: 0.58;
305
+ background-image: repeating-linear-gradient(
306
+ 135deg,
307
+ rgba(99, 112, 131, 0.08) 0 8px,
308
+ transparent 8px 16px
309
+ );
310
+ }
311
+ .entry-head {
312
+ display: flex;
313
+ gap: 8px;
314
+ align-items: center;
315
+ justify-content: space-between;
316
+ }
317
+ .entry-title {
318
+ min-width: 0;
319
+ overflow-wrap: anywhere;
320
+ }
321
+ .entry-actions {
322
+ display: flex;
323
+ gap: 6px;
324
+ align-items: center;
325
+ margin-left: 8px;
326
+ }
327
+ .toolbar-group {
328
+ display: flex;
329
+ flex-wrap: wrap;
330
+ gap: 6px;
331
+ align-items: center;
332
+ }
333
+ .section-head {
334
+ align-items: center;
335
+ display: flex;
336
+ gap: 8px;
337
+ justify-content: space-between;
338
+ }
339
+ .editor-section {
340
+ border-top: 1px solid #d8e0ea;
341
+ margin-top: 14px;
342
+ padding-top: 12px;
343
+ }
344
+ .editor-section h3 {
345
+ color: #334155;
346
+ font-size: 12px;
347
+ letter-spacing: 0;
348
+ margin: 0 0 8px;
349
+ text-transform: uppercase;
350
+ }
351
+ .error-message {
352
+ color: #9f1d1d;
353
+ font-weight: 700;
354
+ }
355
+ .runtime-actions {
356
+ display: flex;
357
+ gap: 8px;
358
+ margin-top: 10px;
359
+ }
360
+ .runtime-group {
361
+ border-top: 1px solid #d8e0ea;
362
+ margin-top: 14px;
363
+ padding-top: 14px;
364
+ }
365
+ .runtime-group:first-of-type {
366
+ border-top: 0;
367
+ margin-top: 0;
368
+ padding-top: 0;
369
+ }
370
+ .runtime-group h3 {
371
+ color: #334155;
372
+ font-size: 12px;
373
+ letter-spacing: 0;
374
+ margin: 0 0 10px;
375
+ text-transform: uppercase;
376
+ }
377
+ .runtime-command-group {
378
+ display: grid;
379
+ gap: 10px;
380
+ }
381
+ .runtime-command-group .runtime-actions {
382
+ margin-top: 0;
383
+ }
384
+ .cookie-header {
385
+ color: #637083;
386
+ display: grid;
387
+ font-size: 11px;
388
+ font-weight: 700;
389
+ gap: 8px;
390
+ grid-template-columns: minmax(120px, 0.85fr) minmax(170px, 1.15fr) 48px 36px;
391
+ margin-top: 8px;
392
+ text-transform: uppercase;
393
+ }
394
+ .cookie-list {
395
+ display: grid;
396
+ gap: 8px;
397
+ margin-top: 6px;
398
+ }
399
+ .cookie-row {
400
+ display: grid;
401
+ grid-template-columns: minmax(120px, 0.85fr) minmax(170px, 1.15fr) 48px 36px;
402
+ gap: 8px;
403
+ align-items: center;
404
+ }
405
+ .cookie-row input {
406
+ min-width: 0;
407
+ }
408
+ .cookie-row button {
409
+ height: 34px;
410
+ min-width: 0;
411
+ padding: 0;
412
+ }
413
+ .cookie-actions {
414
+ margin-top: 10px;
415
+ }
416
+ .cookie-actions button {
417
+ flex: 1;
418
+ }
419
+ .hidden {
420
+ display: none;
421
+ }
422
+ pre {
423
+ white-space: pre-wrap;
424
+ word-break: break-word;
425
+ background: #101820;
426
+ color: #d7f2ff;
427
+ border-radius: 6px;
428
+ padding: 10px;
429
+ overflow: visible;
430
+ }
431
+ .pill {
432
+ display: inline-block;
433
+ border-radius: 999px;
434
+ background: #edf2f7;
435
+ padding: 2px 8px;
436
+ font-size: 12px;
437
+ margin-left: 6px;
438
+ }
439
+ .status-2xx .status-pill {
440
+ background: #d9ecff;
441
+ color: #104f91;
442
+ }
443
+ .status-3xx .status-pill {
444
+ background: #d7f0f2;
445
+ color: #28666b;
446
+ }
447
+ .status-4xx .status-pill {
448
+ background: #ffe4bf;
449
+ color: #8a4a00;
450
+ }
451
+ .status-5xx .status-pill {
452
+ background: #ffd2d2;
453
+ color: #8b1e1e;
454
+ }
455
+ .switch {
456
+ align-items: center;
457
+ display: inline-flex;
458
+ gap: 8px;
459
+ flex: 0 0 auto;
460
+ }
461
+ .switch input {
462
+ display: none;
463
+ }
464
+ .slider {
465
+ width: 42px;
466
+ height: 22px;
467
+ background: #b6c0ce;
468
+ border-radius: 999px;
469
+ position: relative;
470
+ transition: background 0.12s ease;
471
+ }
472
+ .slider::after {
473
+ content: "";
474
+ width: 18px;
475
+ height: 18px;
476
+ background: #fff;
477
+ border-radius: 50%;
478
+ left: 2px;
479
+ top: 2px;
480
+ position: absolute;
481
+ transition: transform 0.12s ease;
482
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
483
+ }
484
+ .switch input:checked + .slider {
485
+ background: #2457d6;
486
+ }
487
+ .switch input:checked + .slider::after {
488
+ transform: translateX(20px);
489
+ }
490
+ @media (max-width: 900px) {
491
+ main {
492
+ grid-template-columns: 1fr;
493
+ }
494
+ main > div {
495
+ max-height: none;
496
+ overflow: visible;
497
+ position: static;
498
+ top: auto;
499
+ }
500
+ .panel-sticky {
501
+ position: static;
502
+ top: auto;
503
+ width: auto;
504
+ }
505
+ .panel.active {
506
+ padding-top: 0;
507
+ }
508
+ }