@innertia-solutions/innertia-nuxt 0.1.66 → 0.1.67
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/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { defineEventHandler, getRouterParam, getQuery, sendRedirect, createError } from 'h3'
|
|
1
|
+
import { defineEventHandler, getRouterParam, getQuery, sendRedirect, createError, getRequestHeader } from 'h3'
|
|
2
2
|
import { writeSession } from '../../../utils/session'
|
|
3
3
|
import { normalizeLoginResponse } from '../../../utils/login'
|
|
4
|
+
import { forwardClientHeaders } from '../../../utils/bff'
|
|
4
5
|
|
|
5
6
|
// Recibe el callback de OAuth, intercambia contra Laravel, sella la sesión y
|
|
6
7
|
// redirige a la app. El token nunca llega al browser.
|
|
@@ -12,7 +13,7 @@ export default defineEventHandler(async (event) => {
|
|
|
12
13
|
let data: any
|
|
13
14
|
try {
|
|
14
15
|
data = await $fetch(`${config.apiInternalUrl}/auth/${provider}/callback`, {
|
|
15
|
-
method: 'GET', query, headers: { Accept: 'application/json' },
|
|
16
|
+
method: 'GET', query, headers: { Accept: 'application/json', ...forwardClientHeaders(n => getRequestHeader(event, n)) },
|
|
16
17
|
})
|
|
17
18
|
} catch (err: any) {
|
|
18
19
|
const msg = err?.data?.message ?? 'oauth_failed'
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { defineEventHandler, readBody, createError } from 'h3'
|
|
1
|
+
import { defineEventHandler, readBody, createError, getRequestHeader } from 'h3'
|
|
2
2
|
import { writeSession } from '../../utils/session'
|
|
3
|
+
import { forwardClientHeaders } from '../../utils/bff'
|
|
3
4
|
import { normalizeLoginResponse } from '../../utils/login'
|
|
4
5
|
|
|
5
6
|
// Llama a Laravel /auth/login server-to-server; en éxito sella el JWT en la
|
|
@@ -13,7 +14,7 @@ export default defineEventHandler(async (event) => {
|
|
|
13
14
|
data = await $fetch(`${config.apiInternalUrl}/auth/login`, {
|
|
14
15
|
method: 'POST',
|
|
15
16
|
body: { context, email, password, remember },
|
|
16
|
-
headers: { Accept: 'application/json' },
|
|
17
|
+
headers: { Accept: 'application/json', ...forwardClientHeaders(n => getRequestHeader(event, n)) },
|
|
17
18
|
})
|
|
18
19
|
} catch (err: any) {
|
|
19
20
|
const status = err?.response?.status ?? err?.statusCode ?? 500
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { defineEventHandler, readBody, createError } from 'h3'
|
|
1
|
+
import { defineEventHandler, readBody, createError, getRequestHeader } from 'h3'
|
|
2
2
|
import { writeSession } from '../../../utils/session'
|
|
3
|
+
import { forwardClientHeaders } from '../../../utils/bff'
|
|
3
4
|
import { normalizeLoginResponse } from '../../../utils/login'
|
|
4
5
|
|
|
5
6
|
// Login de plataforma (identidad separada, sin contexto de tenant). Llama a
|
|
@@ -15,7 +16,7 @@ export default defineEventHandler(async (event) => {
|
|
|
15
16
|
data = await $fetch(`${config.apiInternalUrl}/platform/auth/login`, {
|
|
16
17
|
method: 'POST',
|
|
17
18
|
body: { email, password },
|
|
18
|
-
headers: { Accept: 'application/json' },
|
|
19
|
+
headers: { Accept: 'application/json', ...forwardClientHeaders(n => getRequestHeader(event, n)) },
|
|
19
20
|
})
|
|
20
21
|
} catch (err: any) {
|
|
21
22
|
const status = err?.response?.status ?? err?.statusCode ?? 500
|
|
@@ -20,3 +20,21 @@ describe('buildAuthHeaders', () => {
|
|
|
20
20
|
expect(buildAuthHeaders(undefined)).toEqual({ cookie: '' })
|
|
21
21
|
})
|
|
22
22
|
})
|
|
23
|
+
|
|
24
|
+
describe('forwardClientHeaders', () => {
|
|
25
|
+
it('reenvía solo IP y user-agent del cliente, omitiendo los ausentes', async () => {
|
|
26
|
+
const { forwardClientHeaders } = await import('../bff')
|
|
27
|
+
const headers: Record<string, string> = {
|
|
28
|
+
'x-forwarded-for': '200.1.2.3, 172.68.0.1',
|
|
29
|
+
'cf-connecting-ip': '200.1.2.3',
|
|
30
|
+
'user-agent': 'Mozilla/5.0',
|
|
31
|
+
cookie: 'innertia_session=secret',
|
|
32
|
+
authorization: 'Bearer x',
|
|
33
|
+
}
|
|
34
|
+
expect(forwardClientHeaders(n => headers[n])).toEqual({
|
|
35
|
+
'x-forwarded-for': '200.1.2.3, 172.68.0.1',
|
|
36
|
+
'cf-connecting-ip': '200.1.2.3',
|
|
37
|
+
'user-agent': 'Mozilla/5.0',
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
})
|
package/server/utils/bff.ts
CHANGED
|
@@ -18,3 +18,22 @@ export function resolveApiTarget(base: string, path: string, search: string): st
|
|
|
18
18
|
export function buildAuthHeaders(token?: string): Record<string, string> {
|
|
19
19
|
return token ? { authorization: `Bearer ${token}`, cookie: '' } : { cookie: '' }
|
|
20
20
|
}
|
|
21
|
+
|
|
22
|
+
/** Headers del cliente que Laravel necesita para conocer su IP real y dispositivo. */
|
|
23
|
+
const CLIENT_HEADERS = ['x-forwarded-for', 'x-real-ip', 'cf-connecting-ip', 'user-agent'] as const
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Headers del cliente original a reenviar en las llamadas server-to-server
|
|
27
|
+
* (login, login de plataforma, callback OAuth, logout). Sin esto Laravel ve a
|
|
28
|
+
* TODOS los usuarios con la IP del contenedor Nuxt: el throttle de login queda
|
|
29
|
+
* compartido entre todos (un atacante bloquea el login de todos) y las
|
|
30
|
+
* sesiones quedan sin IP ni dispositivo. Recibe un getter para no depender de h3.
|
|
31
|
+
*/
|
|
32
|
+
export function forwardClientHeaders(get: (name: string) => string | undefined | null): Record<string, string> {
|
|
33
|
+
const out: Record<string, string> = {}
|
|
34
|
+
for (const name of CLIENT_HEADERS) {
|
|
35
|
+
const value = get(name)
|
|
36
|
+
if (value) out[name] = value
|
|
37
|
+
}
|
|
38
|
+
return out
|
|
39
|
+
}
|