@oktis-works/api 0.1.4 → 0.1.7
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/dist/index.js +15 -26
- package/dist/index.js.map +1 -1
- package/dist/middleware/auth.d.ts +2 -2
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +7 -4
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/csrf.d.ts +10 -6
- package/dist/middleware/csrf.d.ts.map +1 -1
- package/dist/middleware/csrf.js +27 -8
- package/dist/middleware/csrf.js.map +1 -1
- package/dist/routes/audit-logs/index.d.ts +1 -1
- package/dist/routes/audit-logs/index.d.ts.map +1 -1
- package/dist/routes/auth/index.d.ts +1 -1
- package/dist/routes/auth/index.d.ts.map +1 -1
- package/dist/routes/auth/index.js +97 -15
- package/dist/routes/auth/index.js.map +1 -1
- package/dist/routes/builds/index.d.ts +4 -0
- package/dist/routes/builds/index.d.ts.map +1 -0
- package/dist/routes/builds/index.js +45 -0
- package/dist/routes/builds/index.js.map +1 -0
- package/dist/routes/categories/index.d.ts +1 -1
- package/dist/routes/categories/index.d.ts.map +1 -1
- package/dist/routes/content/index.d.ts +1 -1
- package/dist/routes/content/index.d.ts.map +1 -1
- package/dist/routes/content/index.js +86 -1
- package/dist/routes/content/index.js.map +1 -1
- package/dist/routes/content-types/index.d.ts +1 -1
- package/dist/routes/content-types/index.d.ts.map +1 -1
- package/dist/routes/deployments/index.d.ts +1 -1
- package/dist/routes/deployments/index.d.ts.map +1 -1
- package/dist/routes/deployments/index.js +14 -1
- package/dist/routes/deployments/index.js.map +1 -1
- package/dist/routes/docs/index.d.ts +1 -1
- package/dist/routes/docs/index.d.ts.map +1 -1
- package/dist/routes/docs/index.js +1 -0
- package/dist/routes/docs/index.js.map +1 -1
- package/dist/routes/events/index.d.ts +1 -1
- package/dist/routes/events/index.d.ts.map +1 -1
- package/dist/routes/field-groups/index.d.ts +1 -1
- package/dist/routes/field-groups/index.d.ts.map +1 -1
- package/dist/routes/field-types/index.d.ts +1 -1
- package/dist/routes/field-types/index.d.ts.map +1 -1
- package/dist/routes/health/index.d.ts +1 -1
- package/dist/routes/health/index.d.ts.map +1 -1
- package/dist/routes/hooks/index.d.ts +1 -1
- package/dist/routes/hooks/index.d.ts.map +1 -1
- package/dist/routes/media/index.d.ts +1 -1
- package/dist/routes/media/index.d.ts.map +1 -1
- package/dist/routes/media/index.js +135 -19
- package/dist/routes/media/index.js.map +1 -1
- package/dist/routes/menus/index.d.ts +1 -1
- package/dist/routes/menus/index.d.ts.map +1 -1
- package/dist/routes/metrics/index.d.ts +1 -1
- package/dist/routes/metrics/index.d.ts.map +1 -1
- package/dist/routes/pages/index.d.ts +1 -1
- package/dist/routes/pages/index.d.ts.map +1 -1
- package/dist/routes/plugins/index.d.ts +1 -1
- package/dist/routes/plugins/index.d.ts.map +1 -1
- package/dist/routes/posts/index.d.ts +1 -1
- package/dist/routes/posts/index.d.ts.map +1 -1
- package/dist/routes/roles/index.d.ts +1 -1
- package/dist/routes/roles/index.d.ts.map +1 -1
- package/dist/routes/settings/index.d.ts +1 -1
- package/dist/routes/settings/index.d.ts.map +1 -1
- package/dist/routes/shared/content-collection.d.ts.map +1 -1
- package/dist/routes/shared/content-collection.js +4 -0
- package/dist/routes/shared/content-collection.js.map +1 -1
- package/dist/routes/tags/index.d.ts +1 -1
- package/dist/routes/tags/index.d.ts.map +1 -1
- package/dist/routes/taxonomies/index.d.ts +1 -1
- package/dist/routes/taxonomies/index.d.ts.map +1 -1
- package/dist/routes/tenants/index.d.ts +1 -1
- package/dist/routes/tenants/index.d.ts.map +1 -1
- package/dist/routes/themes/index.d.ts +1 -1
- package/dist/routes/themes/index.d.ts.map +1 -1
- package/dist/routes/users/index.d.ts +1 -1
- package/dist/routes/users/index.d.ts.map +1 -1
- package/dist/routes/users/index.js +94 -4
- package/dist/routes/users/index.js.map +1 -1
- package/dist/routes/webhooks/index.d.ts +1 -1
- package/dist/routes/webhooks/index.d.ts.map +1 -1
- package/dist/routes/webhooks/index.js +1 -1
- package/dist/routes/webhooks/index.js.map +1 -1
- package/dist/storage.d.ts +17 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +95 -0
- package/dist/storage.js.map +1 -0
- package/dist/utils/csrf.d.ts +6 -0
- package/dist/utils/csrf.d.ts.map +1 -0
- package/dist/utils/csrf.js +29 -0
- package/dist/utils/csrf.js.map +1 -0
- package/package.json +8 -8
- package/dist/middleware/csrf.test.d.ts +0 -2
- package/dist/middleware/csrf.test.d.ts.map +0 -1
- package/dist/middleware/csrf.test.js +0 -94
- package/dist/middleware/csrf.test.js.map +0 -1
- package/dist/middleware/rate-limit.test.d.ts +0 -2
- package/dist/middleware/rate-limit.test.d.ts.map +0 -1
- package/dist/middleware/rate-limit.test.js +0 -58
- package/dist/middleware/rate-limit.test.js.map +0 -1
- package/dist/middleware/trace.test.d.ts +0 -2
- package/dist/middleware/trace.test.d.ts.map +0 -1
- package/dist/middleware/trace.test.js +0 -27
- package/dist/middleware/trace.test.js.map +0 -1
- package/dist/routes/auth/me.d.ts +0 -4
- package/dist/routes/auth/me.d.ts.map +0 -1
- package/dist/routes/auth/me.js +0 -16
- package/dist/routes/auth/me.js.map +0 -1
- package/dist/routes/metrics/index.test.d.ts +0 -2
- package/dist/routes/metrics/index.test.d.ts.map +0 -1
- package/dist/routes/metrics/index.test.js +0 -64
- package/dist/routes/metrics/index.test.js.map +0 -1
- package/dist/routes/posts/revisions.test.d.ts +0 -2
- package/dist/routes/posts/revisions.test.d.ts.map +0 -1
- package/dist/routes/posts/revisions.test.js +0 -57
- package/dist/routes/posts/revisions.test.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -5,13 +5,11 @@ import { logger } from 'hono/logger';
|
|
|
5
5
|
import { cors } from 'hono/cors';
|
|
6
6
|
import { prettyJSON } from 'hono/pretty-json';
|
|
7
7
|
import { serve } from '@hono/node-server';
|
|
8
|
-
import { bootstrap, getEventBus, registerEventAuditLog } from '@oktis-works/core';
|
|
8
|
+
import { bootstrap, getEventBus, registerEventAuditLog, establishTenantContext } from '@oktis-works/core';
|
|
9
9
|
import { traceMiddleware } from './middleware/trace.js';
|
|
10
10
|
import { rateLimitMiddleware } from './middleware/rate-limit.js';
|
|
11
|
-
import { csrfMiddleware
|
|
12
|
-
import { establishTenantContext } from '@oktis-works/core';
|
|
11
|
+
import { csrfMiddleware } from './middleware/csrf.js';
|
|
13
12
|
import authRouter from './routes/auth/index.js';
|
|
14
|
-
import meRouter from './routes/auth/me.js';
|
|
15
13
|
import contentRouter from './routes/content/index.js';
|
|
16
14
|
import postsRouter from './routes/posts/index.js';
|
|
17
15
|
import pagesRouter from './routes/pages/index.js';
|
|
@@ -27,6 +25,7 @@ import settingsRouter from './routes/settings/index.js';
|
|
|
27
25
|
import pluginsRouter from './routes/plugins/index.js';
|
|
28
26
|
import themesRouter from './routes/themes/index.js';
|
|
29
27
|
import deploymentsRouter from './routes/deployments/index.js';
|
|
28
|
+
import buildsRouter from './routes/builds/index.js';
|
|
30
29
|
import eventsRouter from './routes/events/index.js';
|
|
31
30
|
import webhooksRouter from './routes/webhooks/index.js';
|
|
32
31
|
import contentTypesRouter from './routes/content-types/index.js';
|
|
@@ -47,20 +46,18 @@ async function main() {
|
|
|
47
46
|
app.use('*', traceMiddleware);
|
|
48
47
|
app.use('*', logger());
|
|
49
48
|
app.use('*', cors({
|
|
50
|
-
origin:
|
|
49
|
+
origin: (origin) => {
|
|
50
|
+
// Allow admin origins with credentials (cookies HttpOnly)
|
|
51
|
+
const allowed = ['http://admin.lvh.me:3011', 'http://localhost:3011', 'http://127.0.0.1:3011'];
|
|
52
|
+
return allowed.includes(origin) ? origin : '';
|
|
53
|
+
},
|
|
51
54
|
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
|
52
|
-
allowHeaders: ['Content-Type', 'Authorization', 'X-Tenant-ID'],
|
|
55
|
+
allowHeaders: ['Content-Type', 'Authorization', 'X-Tenant-ID', 'X-CSRF-Token'],
|
|
56
|
+
credentials: true,
|
|
53
57
|
}));
|
|
54
58
|
app.use('*', prettyJSON());
|
|
55
59
|
// rest-api-003: rate limiting global (429 + Retry-After); probes isentos
|
|
56
60
|
app.use('*', rateLimitMiddleware());
|
|
57
|
-
// security-001: emissão de cookie CSRF + validação double-submit
|
|
58
|
-
app.use('*', async (c, next) => {
|
|
59
|
-
if (!c.req.header('Cookie')?.includes(CSRF_COOKIE)) {
|
|
60
|
-
c.header('Set-Cookie', `${CSRF_COOKIE}=${issueCsrfToken()}; Path=/; SameSite=Lax; Secure`);
|
|
61
|
-
}
|
|
62
|
-
await next();
|
|
63
|
-
});
|
|
64
61
|
app.use('/api/*', csrfMiddleware);
|
|
65
62
|
// Tenant context middleware
|
|
66
63
|
app.use('*', async (c, next) => {
|
|
@@ -72,9 +69,9 @@ async function main() {
|
|
|
72
69
|
});
|
|
73
70
|
// Health routes (no auth required)
|
|
74
71
|
app.route('/health', healthRouter);
|
|
75
|
-
// API routes
|
|
72
|
+
// API routes (GET /auth/me vive em routes/auth/index.ts — mais completa:
|
|
73
|
+
// roles + tenantId + fallback Bearer; a duplicata routes/auth/me.ts foi removida)
|
|
76
74
|
app.route('/api/v1/auth', authRouter);
|
|
77
|
-
app.route('/api/v1/auth', meRouter);
|
|
78
75
|
app.route('/api/v1/users', usersRouter);
|
|
79
76
|
app.route('/api/v1/tenants', tenantsRouter);
|
|
80
77
|
app.route('/api/v1/roles', rolesRouter);
|
|
@@ -89,6 +86,7 @@ async function main() {
|
|
|
89
86
|
app.route('/api/v1/plugins', pluginsRouter);
|
|
90
87
|
app.route('/api/v1/themes', themesRouter);
|
|
91
88
|
app.route('/api/v1/deployments', deploymentsRouter);
|
|
89
|
+
app.route('/api/v1/builds', buildsRouter);
|
|
92
90
|
app.route('/api/v1/events', eventsRouter);
|
|
93
91
|
app.route('/api/v1/webhooks', webhooksRouter);
|
|
94
92
|
app.route('/api/v1/content-types', contentTypesRouter);
|
|
@@ -98,11 +96,8 @@ async function main() {
|
|
|
98
96
|
app.route('/api/v1/health', healthRouter);
|
|
99
97
|
app.route('/api/v1/metrics', metricsRouter);
|
|
100
98
|
app.route('/api/v1/audit-logs', auditLogsRouter);
|
|
101
|
-
// rest-api-004: documento OpenAPI 3.1
|
|
102
99
|
app.route('/api/v1/docs', docsRouter);
|
|
103
|
-
// REQU-035-002: catálogo de hooks
|
|
104
100
|
app.route('/api/v1/hooks/catalog', hooksCatalogRouter);
|
|
105
|
-
// API info endpoint
|
|
106
101
|
app.get('/api', (c) => {
|
|
107
102
|
return c.json({
|
|
108
103
|
name: 'OkCMS API',
|
|
@@ -125,6 +120,7 @@ async function main() {
|
|
|
125
120
|
plugins: '/api/v1/plugins',
|
|
126
121
|
themes: '/api/v1/themes',
|
|
127
122
|
deployments: '/api/v1/deployments',
|
|
123
|
+
builds: '/api/v1/builds',
|
|
128
124
|
events: '/api/v1/events',
|
|
129
125
|
webhooks: '/api/v1/webhooks',
|
|
130
126
|
contentTypes: '/api/v1/content-types',
|
|
@@ -134,24 +130,17 @@ async function main() {
|
|
|
134
130
|
},
|
|
135
131
|
});
|
|
136
132
|
});
|
|
137
|
-
// 404 handler
|
|
138
133
|
app.notFound((c) => {
|
|
139
134
|
return c.json({ error: 'Not found' }, 404);
|
|
140
135
|
});
|
|
141
|
-
// Error handler
|
|
142
136
|
app.onError((err, c) => {
|
|
143
137
|
console.error('Server error:', err);
|
|
144
138
|
return c.json({ error: 'Internal server error' }, 500);
|
|
145
139
|
});
|
|
146
|
-
// Start server
|
|
147
140
|
const port = Number(process.env['PORT'] ?? 3000);
|
|
148
|
-
serve({
|
|
149
|
-
fetch: app.fetch,
|
|
150
|
-
port,
|
|
151
|
-
}, (info) => {
|
|
141
|
+
serve({ fetch: app.fetch, port }, (info) => {
|
|
152
142
|
console.log(`OkCMS API running on http://localhost:${info.port}`);
|
|
153
143
|
});
|
|
154
|
-
// Graceful shutdown
|
|
155
144
|
process.on('SIGTERM', async () => {
|
|
156
145
|
console.log('SIGTERM received, shutting down...');
|
|
157
146
|
await lifecycle.stop();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,sCAAsC;AAEtC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,sCAAsC;AAEtC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC1G,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,UAAU,MAAM,wBAAwB,CAAC;AAChD,OAAO,aAAa,MAAM,2BAA2B,CAAC;AACtD,OAAO,WAAW,MAAM,yBAAyB,CAAC;AAClD,OAAO,WAAW,MAAM,yBAAyB,CAAC;AAClD,OAAO,YAAY,MAAM,0BAA0B,CAAC;AACpD,OAAO,WAAW,MAAM,yBAAyB,CAAC;AAClD,OAAO,aAAa,MAAM,2BAA2B,CAAC;AACtD,OAAO,WAAW,MAAM,yBAAyB,CAAC;AAClD,OAAO,WAAW,MAAM,yBAAyB,CAAC;AAClD,OAAO,gBAAgB,MAAM,8BAA8B,CAAC;AAC5D,OAAO,UAAU,MAAM,wBAAwB,CAAC;AAChD,OAAO,WAAW,MAAM,yBAAyB,CAAC;AAClD,OAAO,cAAc,MAAM,4BAA4B,CAAC;AACxD,OAAO,aAAa,MAAM,2BAA2B,CAAC;AACtD,OAAO,YAAY,MAAM,0BAA0B,CAAC;AACpD,OAAO,iBAAiB,MAAM,+BAA+B,CAAC;AAC9D,OAAO,YAAY,MAAM,0BAA0B,CAAC;AACpD,OAAO,YAAY,MAAM,0BAA0B,CAAC;AACpD,OAAO,cAAc,MAAM,4BAA4B,CAAC;AACxD,OAAO,kBAAkB,MAAM,iCAAiC,CAAC;AACjE,OAAO,gBAAgB,MAAM,8BAA8B,CAAC;AAC5D,OAAO,iBAAiB,MAAM,gCAAgC,CAAC;AAC/D,OAAO,gBAAgB,MAAM,+BAA+B,CAAC;AAC7D,OAAO,aAAa,MAAM,2BAA2B,CAAC;AACtD,OAAO,eAAe,MAAM,8BAA8B,CAAC;AAC3D,OAAO,UAAU,MAAM,wBAAwB,CAAC;AAChD,OAAO,kBAAkB,MAAM,yBAAyB,CAAC;AAEzD,KAAK,UAAU,IAAI;IACjB,yBAAyB;IACzB,MAAM,SAAS,GAAG,MAAM,SAAS,EAAE,CAAC;IAEpC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,mDAAmD;IACnD,qBAAqB,CAAC,WAAW,EAAE,CAAC,CAAC;IAErC,oBAAoB;IACpB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IAC9B,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;IACvB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC;QAChB,MAAM,EAAE,CAAC,MAAc,EAAE,EAAE;YACzB,0DAA0D;YAC1D,MAAM,OAAO,GAAG,CAAC,0BAA0B,EAAE,uBAAuB,EAAE,uBAAuB,CAAC,CAAC;YAC/F,OAAO,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,CAAC;QACD,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC;QAClE,YAAY,EAAE,CAAC,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,CAAC;QAC9E,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC,CAAC;IACJ,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;IAE3B,yEAAyE;IACzE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAEpC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IAElC,4BAA4B;IAC5B,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAExE,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,mCAAmC;IACnC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IAEnC,yEAAyE;IACzE,kFAAkF;IAClF,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;IACtC,GAAG,CAAC,KAAK,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;IACxC,GAAG,CAAC,KAAK,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC;IAC5C,GAAG,CAAC,KAAK,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;IACxC,GAAG,CAAC,KAAK,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;IACxC,GAAG,CAAC,KAAK,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC;IAC5C,GAAG,CAAC,KAAK,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;IACxC,GAAG,CAAC,KAAK,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;IACxC,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,CAAC;IAClD,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;IACtC,GAAG,CAAC,KAAK,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;IACxC,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;IAC9C,GAAG,CAAC,KAAK,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC;IAC5C,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC;IAC1C,GAAG,CAAC,KAAK,CAAC,qBAAqB,EAAE,iBAAiB,CAAC,CAAC;IACpD,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC;IAC1C,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC;IAC1C,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;IAC9C,GAAG,CAAC,KAAK,CAAC,uBAAuB,EAAE,kBAAkB,CAAC,CAAC;IACvD,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,CAAC;IAClD,GAAG,CAAC,KAAK,CAAC,sBAAsB,EAAE,iBAAiB,CAAC,CAAC;IACrD,GAAG,CAAC,KAAK,CAAC,qBAAqB,EAAE,gBAAgB,CAAC,CAAC;IACnD,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC;IAC1C,GAAG,CAAC,KAAK,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC;IAC5C,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAAC;IACjD,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;IACtC,GAAG,CAAC,KAAK,CAAC,uBAAuB,EAAE,kBAAkB,CAAC,CAAC;IAEvD,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;QACpB,OAAO,CAAC,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,OAAO;YAChB,WAAW,EAAE,gCAAgC;YAC7C,SAAS,EAAE;gBACT,MAAM,EAAE,SAAS;gBACjB,IAAI,EAAE,cAAc;gBACpB,KAAK,EAAE,eAAe;gBACtB,OAAO,EAAE,iBAAiB;gBAC1B,KAAK,EAAE,eAAe;gBACtB,KAAK,EAAE,eAAe;gBACtB,OAAO,EAAE,iBAAiB;gBAC1B,KAAK,EAAE,eAAe;gBACtB,KAAK,EAAE,eAAe;gBACtB,UAAU,EAAE,oBAAoB;gBAChC,IAAI,EAAE,cAAc;gBACpB,KAAK,EAAE,eAAe;gBACtB,QAAQ,EAAE,kBAAkB;gBAC5B,OAAO,EAAE,iBAAiB;gBAC1B,MAAM,EAAE,gBAAgB;gBACxB,WAAW,EAAE,qBAAqB;gBAClC,MAAM,EAAE,gBAAgB;gBACxB,MAAM,EAAE,gBAAgB;gBACxB,QAAQ,EAAE,kBAAkB;gBAC5B,YAAY,EAAE,uBAAuB;gBACrC,UAAU,EAAE,oBAAoB;gBAChC,WAAW,EAAE,sBAAsB;gBACnC,UAAU,EAAE,qBAAqB;aAClC;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QACrB,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;QACpC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC;IAEjD,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;QACzC,OAAO,CAAC,GAAG,CAAC,yCAAyC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QAC/B,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;QAClD,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QAC9B,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;QACjD,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;IAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Context, Next } from 'hono';
|
|
2
2
|
export declare const authMiddleware: (c: Context, next: Next) => Promise<(Response & import("hono").TypedResponse<{
|
|
3
3
|
error: string;
|
|
4
|
-
}>) | undefined>;
|
|
4
|
+
}, 401, "json">) | undefined>;
|
|
5
5
|
export declare const requirePermission: (action: string, resource: string) => (c: Context, next: Next) => Promise<(Response & import("hono").TypedResponse<{
|
|
6
6
|
error: string;
|
|
7
|
-
}>) | undefined>;
|
|
7
|
+
}, 403, "json">) | undefined>;
|
|
8
8
|
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAQ1C,eAAO,MAAM,cAAc,MAAa,OAAO,QAAQ,IAAI;;6BAwB1D,CAAC;AAEF,eAAO,MAAM,iBAAiB,WAAY,MAAM,YAAY,MAAM,SAC/C,OAAO,QAAQ,IAAI;;6BASrC,CAAC"}
|
package/dist/middleware/auth.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
// @oktis-works/api - Authentication Middleware
|
|
1
|
+
// @oktis-works/api - Authentication Middleware (Bearer + HttpOnly cookie via hono/cookie)
|
|
2
|
+
import { getCookie } from 'hono/cookie';
|
|
2
3
|
import { AuthService } from '@oktis-works/auth';
|
|
3
4
|
import { loadConfig } from '@oktis-works/config';
|
|
4
5
|
const config = loadConfig();
|
|
5
6
|
const authService = new AuthService(config.auth);
|
|
6
7
|
export const authMiddleware = async (c, next) => {
|
|
8
|
+
// Bearer primeiro (clientes API-first), depois cookie HttpOnly (admin/navegador)
|
|
7
9
|
const authHeader = c.req.header('Authorization');
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
const cookieToken = getCookie(c, 'access_token');
|
|
11
|
+
const token = authHeader?.startsWith('Bearer ') ? authHeader.slice(7) : cookieToken;
|
|
12
|
+
if (!token) {
|
|
13
|
+
return c.json({ error: 'Missing or invalid authorization header/cookie' }, 401);
|
|
10
14
|
}
|
|
11
|
-
const token = authHeader.slice(7);
|
|
12
15
|
const payload = await authService.verifyToken(token);
|
|
13
16
|
if (!payload) {
|
|
14
17
|
return c.json({ error: 'Invalid or expired token' }, 401);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAG1F,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAC5B,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAEjD,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAAE,CAAU,EAAE,IAAU,EAAE,EAAE;IAC7D,iFAAiF;IACjF,MAAM,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;IAEjD,MAAM,KAAK,GAAG,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IAEpF,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gDAAgD,EAAE,EAAE,GAAG,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAErD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,EAAE,GAAG,CAAC,CAAC;IAC5D,CAAC;IAED,mBAAmB;IACnB,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAElC,MAAM,IAAI,EAAE,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAc,EAAE,QAAgB,EAAE,EAAE;IACpE,OAAO,KAAK,EAAE,CAAU,EAAE,IAAU,EAAE,EAAE;QACtC,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAa,CAAC;QAEjD,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;YAC5D,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,EAAE,GAAG,CAAC,CAAC;QAC5D,CAAC;QAED,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import type { Context, Next } from 'hono';
|
|
2
|
-
export declare const CSRF_COOKIE
|
|
3
|
-
export declare const CSRF_HEADER
|
|
2
|
+
export declare const CSRF_COOKIE: string;
|
|
3
|
+
export declare const CSRF_HEADER: string;
|
|
4
4
|
export declare function issueCsrfToken(): string;
|
|
5
5
|
/** Origem esperada: mesma do Host da requisição (ou configurada em TRUSTED_ORIGINS). */
|
|
6
6
|
export declare function isSameOrigin(c: Context): boolean;
|
|
7
7
|
/**
|
|
8
|
-
* Double-submit cookie:
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Double-submit cookie: valida que header X-CSRF-Token === cookie em requisições
|
|
9
|
+
* state-changing de BROWSER (com Origin/Referer).
|
|
10
|
+
* - Bearer (API-first) → isento;
|
|
11
|
+
* - sem Origin/Referer → cliente não-browser (curl/SDK/CI) → isento (CSRF só
|
|
12
|
+
* afeta browsers — navegadores SEMPRE enviam Origin em fetch state-changing);
|
|
13
|
+
* - Origin presente e diferente do Host → só passa se estiver em TRUSTED_ORIGINS
|
|
14
|
+
* (cross-port na mesma máquina, ex. admin:3011 → api:3010).
|
|
11
15
|
*/
|
|
12
|
-
export declare function csrfMiddleware(c: Context, next: Next): Promise<Response |
|
|
16
|
+
export declare function csrfMiddleware(c: Context, next: Next): Promise<Response | void>;
|
|
13
17
|
//# sourceMappingURL=csrf.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../src/middleware/csrf.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../src/middleware/csrf.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAU1C,eAAO,MAAM,WAAW,QAAqB,CAAC;AAC9C,eAAO,MAAM,WAAW,QAAqB,CAAC;AAE9C,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAoBhD;AAWD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAsCrF"}
|
package/dist/middleware/csrf.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
// @oktis-works/api - CSRF via double-submit cookie + verificação de Origin (security-001)
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { loadConfig } from '@oktis-works/config';
|
|
4
|
+
const config = loadConfig();
|
|
5
|
+
const { csrf: csrfCfg } = config.auth;
|
|
3
6
|
const STATE_CHANGING = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
|
|
4
|
-
|
|
5
|
-
export const
|
|
7
|
+
// Cookie CSRF usa o nome do config (padrão: csrf_token)
|
|
8
|
+
export const CSRF_COOKIE = csrfCfg.cookieName;
|
|
9
|
+
export const CSRF_HEADER = csrfCfg.headerName;
|
|
6
10
|
export function issueCsrfToken() {
|
|
7
11
|
return randomUUID();
|
|
8
12
|
}
|
|
@@ -38,20 +42,35 @@ function readCookie(cookieHeader, name) {
|
|
|
38
42
|
return null;
|
|
39
43
|
}
|
|
40
44
|
/**
|
|
41
|
-
* Double-submit cookie:
|
|
42
|
-
*
|
|
43
|
-
*
|
|
45
|
+
* Double-submit cookie: valida que header X-CSRF-Token === cookie em requisições
|
|
46
|
+
* state-changing de BROWSER (com Origin/Referer).
|
|
47
|
+
* - Bearer (API-first) → isento;
|
|
48
|
+
* - sem Origin/Referer → cliente não-browser (curl/SDK/CI) → isento (CSRF só
|
|
49
|
+
* afeta browsers — navegadores SEMPRE enviam Origin em fetch state-changing);
|
|
50
|
+
* - Origin presente e diferente do Host → só passa se estiver em TRUSTED_ORIGINS
|
|
51
|
+
* (cross-port na mesma máquina, ex. admin:3011 → api:3010).
|
|
44
52
|
*/
|
|
45
53
|
export async function csrfMiddleware(c, next) {
|
|
54
|
+
if (!csrfCfg.enabled)
|
|
55
|
+
return next();
|
|
46
56
|
const method = c.req.method.toUpperCase();
|
|
47
57
|
if (!STATE_CHANGING.has(method)) {
|
|
48
58
|
await next();
|
|
49
59
|
return;
|
|
50
60
|
}
|
|
51
|
-
//
|
|
52
|
-
|
|
61
|
+
// Bearer (API-first) é isento de CSRF
|
|
62
|
+
if (c.req.header('Authorization')?.startsWith('Bearer ')) {
|
|
63
|
+
await next();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// Sem Origin/Referer = cliente não-browser (curl/SDK/CI) → CSRF não se aplica
|
|
67
|
+
const origin = c.req.header('Origin') ?? c.req.header('Referer');
|
|
68
|
+
if (!origin) {
|
|
69
|
+
await next();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
53
72
|
const cookieHeader = c.req.header('Cookie');
|
|
54
|
-
if (
|
|
73
|
+
if (cookieHeader?.includes(CSRF_COOKIE)) {
|
|
55
74
|
const cookieToken = readCookie(cookieHeader, CSRF_COOKIE);
|
|
56
75
|
const headerToken = c.req.header(CSRF_HEADER);
|
|
57
76
|
if (!cookieToken || !headerToken || cookieToken !== headerToken || !isSameOrigin(c)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../../src/middleware/csrf.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAG1F,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../../src/middleware/csrf.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
-
declare const router: Hono<import("hono").
|
|
2
|
+
declare const router: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
3
3
|
export default router;
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/audit-logs/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,QAAA,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/audit-logs/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,QAAA,MAAM,MAAM,4EAAa,CAAC;AAkB1B,eAAe,MAAM,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
-
declare const authRouter: Hono<import("hono").
|
|
2
|
+
declare const authRouter: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
3
3
|
export default authRouter;
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/auth/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/auth/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAY5B,QAAA,MAAM,UAAU,4EAAa,CAAC;AA2L9B,eAAe,UAAU,CAAC"}
|
|
@@ -1,21 +1,68 @@
|
|
|
1
|
-
// @oktis-works/api - Auth Routes
|
|
1
|
+
// @oktis-works/api - Auth Routes (HttpOnly cookies via hono/cookie + CSRF)
|
|
2
2
|
import { Hono } from 'hono';
|
|
3
|
+
import { setCookie, getCookie, deleteCookie } from 'hono/cookie';
|
|
3
4
|
import { AuthService } from '@oktis-works/auth';
|
|
4
5
|
import { loadConfig } from '@oktis-works/config';
|
|
5
6
|
import { establishTenantContext } from '@oktis-works/core';
|
|
7
|
+
import { setCsrfCookie } from '../../utils/csrf.js';
|
|
6
8
|
const config = loadConfig();
|
|
7
9
|
const authService = new AuthService(config.auth);
|
|
10
|
+
const { cookie: cookieCfg } = config.auth;
|
|
8
11
|
const authRouter = new Hono();
|
|
12
|
+
// Cookie options from config — None requer Secure (auto em produção)
|
|
13
|
+
const isProd = config.app.nodeEnv === 'production';
|
|
14
|
+
const cookieSecure = cookieCfg.secure ?? isProd;
|
|
15
|
+
const ACCESS_OPTS = {
|
|
16
|
+
httpOnly: true,
|
|
17
|
+
secure: cookieSecure,
|
|
18
|
+
sameSite: cookieCfg.sameSite,
|
|
19
|
+
path: '/',
|
|
20
|
+
maxAge: cookieCfg.accessTokenMaxAge ?? 60 * 15, // 15min
|
|
21
|
+
};
|
|
22
|
+
const REFRESH_OPTS = {
|
|
23
|
+
httpOnly: true,
|
|
24
|
+
secure: cookieSecure,
|
|
25
|
+
sameSite: cookieCfg.sameSite,
|
|
26
|
+
path: '/',
|
|
27
|
+
maxAge: cookieCfg.refreshTokenMaxAge ?? 60 * 60 * 24 * 30, // 30d
|
|
28
|
+
};
|
|
29
|
+
/** Set-Cookie múltiplo: hono/cookie setCookie appenda corretamente. */
|
|
30
|
+
function setAuthCookies(c, accessToken, refreshToken) {
|
|
31
|
+
setCookie(c, 'access_token', accessToken, ACCESS_OPTS);
|
|
32
|
+
setCookie(c, 'refresh_token', refreshToken, REFRESH_OPTS);
|
|
33
|
+
}
|
|
34
|
+
function clearAuthCookies(c) {
|
|
35
|
+
deleteCookie(c, 'access_token', { path: '/' });
|
|
36
|
+
deleteCookie(c, 'refresh_token', { path: '/' });
|
|
37
|
+
}
|
|
38
|
+
// CSRF é validado globalmente em app.use('/api/*', csrfMiddleware) — ver middleware/csrf.ts
|
|
9
39
|
// POST /auth/register
|
|
10
40
|
authRouter.post('/register', async (c) => {
|
|
11
41
|
try {
|
|
12
42
|
const body = await c.req.json();
|
|
13
|
-
const { email, password, name } = body;
|
|
43
|
+
const { email, password, name, tenantId } = body;
|
|
14
44
|
if (!email || !password || !name) {
|
|
15
45
|
return c.json({ error: 'Missing required fields' }, 400);
|
|
16
46
|
}
|
|
17
|
-
|
|
18
|
-
|
|
47
|
+
await authService.register({ email, password, name, tenantId });
|
|
48
|
+
// Auto-login pós-registro: tokens em cookies HttpOnly (nunca no localStorage)
|
|
49
|
+
await establishTenantContext(tenantId ?? 'default');
|
|
50
|
+
const result = await authService.login({
|
|
51
|
+
email,
|
|
52
|
+
password,
|
|
53
|
+
tenantId: tenantId ?? 'default',
|
|
54
|
+
ipAddress: c.req.header('x-forwarded-for') ?? c.req.header('x-real-ip'),
|
|
55
|
+
userAgent: c.req.header('user-agent'),
|
|
56
|
+
});
|
|
57
|
+
setAuthCookies(c, result.accessToken, result.refreshToken);
|
|
58
|
+
setCsrfCookie(c);
|
|
59
|
+
// Tokens no body também: compat com clientes API-first (@oktis-works/api-client)
|
|
60
|
+
return c.json({
|
|
61
|
+
user: result.user,
|
|
62
|
+
tenantId: result.tenantId,
|
|
63
|
+
accessToken: result.accessToken,
|
|
64
|
+
refreshToken: result.refreshToken,
|
|
65
|
+
}, 201);
|
|
19
66
|
}
|
|
20
67
|
catch (error) {
|
|
21
68
|
const message = error instanceof Error ? error.message : 'Registration failed';
|
|
@@ -38,41 +85,53 @@ authRouter.post('/login', async (c) => {
|
|
|
38
85
|
ipAddress: c.req.header('x-forwarded-for') ?? c.req.header('x-real-ip'),
|
|
39
86
|
userAgent: c.req.header('user-agent'),
|
|
40
87
|
});
|
|
41
|
-
|
|
88
|
+
setAuthCookies(c, result.accessToken, result.refreshToken);
|
|
89
|
+
setCsrfCookie(c);
|
|
90
|
+
// Tokens no body também: clientes API-first (@oktis-works/api-client) usam
|
|
91
|
+
// Bearer; o browser continua nos cookies HttpOnly (nunca localStorage).
|
|
92
|
+
return c.json({
|
|
93
|
+
user: result.user,
|
|
94
|
+
tenantId: result.tenantId,
|
|
95
|
+
accessToken: result.accessToken,
|
|
96
|
+
refreshToken: result.refreshToken,
|
|
97
|
+
});
|
|
42
98
|
}
|
|
43
99
|
catch (error) {
|
|
44
100
|
const message = error instanceof Error ? error.message : 'Login failed';
|
|
45
101
|
return c.json({ error: message }, 401);
|
|
46
102
|
}
|
|
47
103
|
});
|
|
48
|
-
// POST /auth/refresh
|
|
104
|
+
// POST /auth/refresh — híbrido: refreshToken do cookie (browser) OU body (API-first);
|
|
105
|
+
// retorna tokens no body (clientes externos) E seta cookies (browser)
|
|
49
106
|
authRouter.post('/refresh', async (c) => {
|
|
50
107
|
try {
|
|
51
|
-
const body = await c.req.json();
|
|
52
|
-
const
|
|
108
|
+
const body = await c.req.json().catch(() => ({}));
|
|
109
|
+
const refreshToken = getCookie(c, 'refresh_token') ?? body['refreshToken'];
|
|
53
110
|
if (!refreshToken) {
|
|
54
111
|
return c.json({ error: 'Missing refresh token' }, 400);
|
|
55
112
|
}
|
|
56
113
|
const tokens = await authService.refreshToken(refreshToken);
|
|
57
114
|
if (!tokens) {
|
|
115
|
+
clearAuthCookies(c);
|
|
58
116
|
return c.json({ error: 'Invalid refresh token' }, 401);
|
|
59
117
|
}
|
|
60
|
-
|
|
118
|
+
setAuthCookies(c, tokens.accessToken, tokens.refreshToken);
|
|
119
|
+
// Tokens no body: compat com clientes API-first (@oktis-works/api-client)
|
|
120
|
+
return c.json({ success: true, accessToken: tokens.accessToken, refreshToken: tokens.refreshToken });
|
|
61
121
|
}
|
|
62
122
|
catch (error) {
|
|
63
123
|
const message = error instanceof Error ? error.message : 'Token refresh failed';
|
|
64
124
|
return c.json({ error: message }, 400);
|
|
65
125
|
}
|
|
66
126
|
});
|
|
67
|
-
// POST /auth/logout
|
|
127
|
+
// POST /auth/logout — encerra sessão pelo refresh_token do cookie
|
|
68
128
|
authRouter.post('/logout', async (c) => {
|
|
69
129
|
try {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return c.json({ error: 'Missing token' }, 400);
|
|
130
|
+
const refreshToken = getCookie(c, 'refresh_token');
|
|
131
|
+
if (refreshToken) {
|
|
132
|
+
await authService.logout(refreshToken);
|
|
74
133
|
}
|
|
75
|
-
|
|
134
|
+
clearAuthCookies(c);
|
|
76
135
|
return c.json({ success: true });
|
|
77
136
|
}
|
|
78
137
|
catch (error) {
|
|
@@ -80,5 +139,28 @@ authRouter.post('/logout', async (c) => {
|
|
|
80
139
|
return c.json({ error: message }, 400);
|
|
81
140
|
}
|
|
82
141
|
});
|
|
142
|
+
// GET /auth/me — sessão atual via cookie (fallback Bearer para clientes API-first)
|
|
143
|
+
authRouter.get('/me', async (c) => {
|
|
144
|
+
try {
|
|
145
|
+
const accessToken = getCookie(c, 'access_token') ?? c.req.header('Authorization')?.slice(7);
|
|
146
|
+
if (!accessToken) {
|
|
147
|
+
return c.json({ error: 'Not authenticated' }, 401);
|
|
148
|
+
}
|
|
149
|
+
const payload = await authService.verifyToken(accessToken);
|
|
150
|
+
if (!payload) {
|
|
151
|
+
return c.json({ error: 'Invalid or expired token' }, 401);
|
|
152
|
+
}
|
|
153
|
+
const sql = (await import('@oktis-works/database')).getConnection();
|
|
154
|
+
const rows = await sql.unsafe('SELECT id, email, name, avatar, status, last_login_at FROM users WHERE id = $1', [payload.sub]);
|
|
155
|
+
if (!rows.length) {
|
|
156
|
+
return c.json({ error: 'User not found' }, 404);
|
|
157
|
+
}
|
|
158
|
+
return c.json({ user: rows[0], tenantId: payload.tenantId, roles: payload.roles });
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
const message = error instanceof Error ? error.message : 'Failed to get user';
|
|
162
|
+
return c.json({ error: message }, 400);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
83
165
|
export default authRouter;
|
|
84
166
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/routes/auth/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/routes/auth/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/builds/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAK5B,QAAA,MAAM,MAAM,4EAAa,CAAC;AAoD1B,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// @oktis-works/api - Builds (pipeline build → deploy)
|
|
2
|
+
// Cria builds (PENDING) e enfileira `build.create` no worker (docker build real).
|
|
3
|
+
import { Hono } from 'hono';
|
|
4
|
+
import { buildService, enqueueJob } from '@oktis-works/core';
|
|
5
|
+
import { CMS_VERSION } from '@oktis-works/validation';
|
|
6
|
+
import { authMiddleware, requirePermission } from '../../middleware/auth.js';
|
|
7
|
+
const router = new Hono();
|
|
8
|
+
router.use('*', authMiddleware);
|
|
9
|
+
router.get('/', requirePermission('read', 'build'), async (c) => {
|
|
10
|
+
const page = Number(c.req.query('page') ?? 1);
|
|
11
|
+
const limit = Number(c.req.query('limit') ?? 20);
|
|
12
|
+
const status = c.req.query('status') || undefined;
|
|
13
|
+
const result = await buildService.list({ page, limit, status });
|
|
14
|
+
return c.json(result);
|
|
15
|
+
});
|
|
16
|
+
router.get('/:id', requirePermission('read', 'build'), async (c) => {
|
|
17
|
+
const id = c.req.param('id');
|
|
18
|
+
const result = await buildService.getById(id);
|
|
19
|
+
if (!result) {
|
|
20
|
+
return c.json({ error: 'Build not found' }, 404);
|
|
21
|
+
}
|
|
22
|
+
return c.json(result);
|
|
23
|
+
});
|
|
24
|
+
// POST / — cria build e dispara o job build.create (worker monta a imagem Docker).
|
|
25
|
+
// Fila opcional: `queued: false` avisa o consumidor API-first que o build roda
|
|
26
|
+
// somente quando Redis/worker estiverem disponíveis (degradação silenciosa).
|
|
27
|
+
router.post('/', requirePermission('create', 'build'), async (c) => {
|
|
28
|
+
try {
|
|
29
|
+
const body = await c.req.json().catch(() => ({}));
|
|
30
|
+
const userId = c.get('userId');
|
|
31
|
+
const tenantId = String(c.get('tenantId') ?? 'default');
|
|
32
|
+
const plugins = (body.plugins ?? {});
|
|
33
|
+
const theme = (body.theme ?? { name: 'default', version: '0.0.0' });
|
|
34
|
+
const coreVersion = typeof body.coreVersion === 'string' && body.coreVersion.length > 0 ? body.coreVersion : CMS_VERSION;
|
|
35
|
+
const result = await buildService.create({ coreVersion, plugins, theme });
|
|
36
|
+
const queued = await enqueueJob('build.create', { buildId: result.id, plugins, theme }, { tenantId, userId, jobId: `build.create:${result.id}` });
|
|
37
|
+
return c.json({ ...result, queued }, 201);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
const message = error instanceof Error ? error.message : 'Failed to create build';
|
|
41
|
+
return c.json({ error: message }, 400);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
export default router;
|
|
45
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/routes/builds/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
-
declare const router: Hono<import("hono").
|
|
2
|
+
declare const router: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
3
3
|
export default router;
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/categories/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,QAAA,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/categories/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,QAAA,MAAM,MAAM,4EAAa,CAAC;AAkD1B,eAAe,MAAM,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
-
declare const contentRouter: Hono<import("hono").
|
|
2
|
+
declare const contentRouter: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
3
3
|
export default contentRouter;
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/content/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/content/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAM5B,QAAA,MAAM,aAAa,4EAAa,CAAC;AAsMjC,eAAe,aAAa,CAAC"}
|