Skip to content

Commit

Permalink
refactor: use request origin for magic-link if hostUrl not provided (#29
Browse files Browse the repository at this point in the history
)

* refactor: use request origin for magic link if hostUrl not provided

* chore: minor test name rearrangement

* chore: remove 'getHostUrl' and its respective tests, along with 'HOST' constant and its calls in test headers.

---------

Co-authored-by: Dev XO <devxo@mail.com>
  • Loading branch information
mw10013 and dev-xo committed Dec 17, 2023
1 parent 6eca590 commit 62163e9
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 52 deletions.
17 changes: 1 addition & 16 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function generateMagicLink(

const url = new URL(
options.callbackPath ?? '/',
options.hostUrl ?? getHostUrl(options.request),
options.hostUrl ?? new URL(options.request.url).origin,
)
url.searchParams.set(options.param, options.code)

Expand Down Expand Up @@ -81,18 +81,3 @@ export async function verifyJWT({ jwt, secretKey }: VerifyJWTOptions) {
throw new Error(ERRORS.INVALID_JWT)
}
}

/**
* Miscellaneous.
*/
export function getHostUrl(request: Request) {
const host = request.headers.get('X-Forwarded-Host') ?? request.headers.get('host')
if (!host) throw new Error('Could not determine host.')

// If the host is localhost or ends with .local, use http.
const protocol = host.match(/(:?\.local|^localhost|^127\.\d+\.\d+\.\d+)(:?:\d+)?$/)
? 'http'
: 'https'

return `${protocol}://${host}`
}
57 changes: 22 additions & 35 deletions test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, test, expect, afterEach, vi } from 'vitest'
import { AuthorizationError } from 'remix-auth'

import { TOTPStrategy } from '../src/index'
import { generateTOTP, generateMagicLink, getHostUrl, signJWT } from '../src/utils'
import { generateTOTP, generateMagicLink, signJWT } from '../src/utils'
import { STRATEGY_NAME, FORM_FIELDS, SESSION_KEYS, ERRORS } from '../src/constants'

import {
Expand Down Expand Up @@ -275,7 +275,6 @@ describe('[ TOTP ]', () => {
const request = new Request(`${HOST_URL}`, {
method: 'POST',
headers: {
host: HOST_URL,
cookie: await sessionStorage.commitSession(session),
},
body: formData,
Expand Down Expand Up @@ -308,7 +307,6 @@ describe('[ TOTP ]', () => {

const request = new Request(`${HOST_URL}`, {
method: 'POST',
headers: { host: HOST_URL },
body: formData,
})

Expand All @@ -334,7 +332,6 @@ describe('[ TOTP ]', () => {

const request = new Request(`${HOST_URL}`, {
method: 'POST',
headers: { host: HOST_URL },
body: formData,
})

Expand Down Expand Up @@ -370,7 +367,6 @@ describe('[ TOTP ]', () => {

const request = new Request(`${HOST_URL}`, {
method: 'POST',
headers: { host: HOST_URL },
body: formData,
})

Expand Down Expand Up @@ -410,7 +406,6 @@ describe('[ TOTP ]', () => {

const request = new Request(`${HOST_URL}`, {
method: 'POST',
headers: { host: HOST_URL },
body: formData,
})

Expand Down Expand Up @@ -450,7 +445,6 @@ describe('[ TOTP ]', () => {
const request = new Request(`${HOST_URL}`, {
method: 'POST',
headers: {
host: HOST_URL,
cookie: await sessionStorage.commitSession(session),
},
body: formData,
Expand Down Expand Up @@ -495,7 +489,6 @@ describe('[ TOTP ]', () => {
const request = new Request(`${HOST_URL}`, {
method: 'POST',
headers: {
host: HOST_URL,
cookie: await sessionStorage.commitSession(session),
},
body: formData,
Expand Down Expand Up @@ -543,9 +536,7 @@ describe('[ TOTP ]', () => {
callbackPath: '/magic-link',
param: 'code',
code: _otp,
request: new Request(HOST_URL, {
headers: { host: HOST_URL },
}),
request: new Request(HOST_URL),
})

const session = await sessionStorage.getSession()
Expand All @@ -554,7 +545,6 @@ describe('[ TOTP ]', () => {
const request = new Request(`${magicLink}`, {
method: 'GET',
headers: {
host: HOST_URL,
cookie: await sessionStorage.commitSession(session),
},
})
Expand Down Expand Up @@ -589,14 +579,11 @@ describe('[ TOTP ]', () => {
callbackPath: '/invalid',
param: 'code',
code: _otp,
request: new Request(HOST_URL, {
headers: { host: HOST_URL },
}),
request: new Request(HOST_URL),
})

const request = new Request(`${magicLink}`, {
method: 'GET',
headers: { host: HOST_URL },
})

const strategy = new TOTPStrategy(
Expand Down Expand Up @@ -635,7 +622,6 @@ describe('[ TOTP ]', () => {
const request = new Request(`${HOST_URL}`, {
method: 'POST',
headers: {
host: HOST_URL,
cookie: await sessionStorage.commitSession(session),
},
body: formData,
Expand Down Expand Up @@ -679,7 +665,6 @@ describe('[ TOTP ]', () => {
const request = new Request(`${HOST_URL}`, {
method: 'POST',
headers: {
host: HOST_URL,
cookie: await sessionStorage.commitSession(session),
},
body: formData,
Expand All @@ -706,25 +691,27 @@ describe('[ TOTP ]', () => {
})

describe('[ Utils ]', () => {
test('Should properly use the HTTP protocol for local environments.', async () => {
const request = new Request(`${HOST_URL}`)
const samples: Array<[string, 'http:' | 'https:']> = [
['127.0.0.1', 'http:'],
['127.1.1.1', 'http:'],
['127.0.0.1:8888', 'http:'],
['localhost', 'http:'],
['localhost:3000', 'http:'],
['remix.run', 'https:'],
['remix.run:3000', 'https:'],
['local.com', 'https:'],
['legit.local.com:3000', 'https:'],
['remix-auth-otp.local', 'http:'],
['remix-auth-otp.local:3000', 'http:'],
test('Should use the origin from the request for the magic-link if hostUrl is not provided.', async () => {
const samples: Array<[string, string]> = [
['http://localhost/login', 'http://localhost/magic-link?code=U2N2EY'],
['http://localhost:3000/login', 'http://localhost:3000/magic-link?code=U2N2EY'],
['http://127.0.0.1/login', 'http://127.0.0.1/magic-link?code=U2N2EY'],
['http://127.0.0.1:3000/login', 'http://127.0.0.1:3000/magic-link?code=U2N2EY'],
['http://localhost:8788/signin', 'http://localhost:8788/magic-link?code=U2N2EY'],
['https://host.com/login', 'https://host.com/magic-link?code=U2N2EY'],
['https://host.com:3000/login', 'https://host.com:3000/magic-link?code=U2N2EY'],
]

for (const [host, protocol] of samples) {
request.headers.set('host', host)
expect(getHostUrl(request).startsWith(protocol)).toBe(true)
for (const [requestUrl, magicLinkUrl] of samples) {
const request = new Request(requestUrl)
expect(
generateMagicLink({
...MAGIC_LINK_GENERATION_DEFAULTS,
param: 'code',
code: 'U2N2EY',
request,
}),
).toBe(magicLinkUrl)
}
})
})
2 changes: 1 addition & 1 deletion test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as crypto from 'crypto'
* Constants.
*/
export const SECRET_ENV = 'SECRET_ENV'
export const HOST_URL = 'localhost:3000'
export const HOST_URL = 'http://localhost:3000'
export const DEFAULT_EMAIL = 'localhost@3000.com'

/**
Expand Down

0 comments on commit 62163e9

Please sign in to comment.