feat: Check if host domain is authorised to use license during log in.

This commit is contained in:
Sam Tolmay 2023-11-22 16:37:28 +02:00
parent afbe5d3b29
commit 09649da028
No known key found for this signature in database
4 changed files with 47 additions and 8 deletions

View File

@ -8,12 +8,8 @@
of this software will be governed by the Apache License, Version 2.0.
*/
import validateLicense from '../validateLicense.js';
function createLicenseRedirectCallback(context) {
function createLicenseRedirectCallback(context, license) {
async function licenseRedirectCallback({ url, baseUrl }) {
const license = await validateLicense(context);
if (license.code !== 'VALID' || !license.entitlements.includes('AUTH')) {
return '/lowdefy/license-invalid';
}

View File

@ -0,0 +1,35 @@
/*
Copyright (C) 2023 Lowdefy, Inc
Use of this software is governed by the Business Source License included in the LICENSE file and at www.mariadb.com/bsl11.
Change Date: 2027-10-09
On the date above, in accordance with the Business Source License, use
of this software will be governed by the Apache License, Version 2.0.
*/
// TODO: Do we call this domain/host/url?
function checkAuthorizedHost({ license, req }) {
const authorizedUrls = license.metadata?.domains ?? [];
if (authorizedUrls.length === 0) {
return true;
}
const protocol = req.socket.encrypted ? 'https://' : 'http://';
const url = `${protocol}${req.headers.host}`;
let match = false;
for (const authorizedUrl of authorizedUrls) {
const test = new RegExp(
`^${authorizedUrl.replaceAll('.', '\\.').replaceAll('*', '.*').replaceAll('/', '\\/')}$`,
'u'
);
if (url.match(test)) {
match = true;
break;
}
}
return match;
}
export default checkAuthorizedHost;

View File

@ -13,6 +13,8 @@ import NextAuth from 'next-auth';
import apiWrapper from '../../../lib/server/apiWrapper.js';
import authJson from '../../../build/auth.json';
import createLicenseRedirectCallback from '../../../lib/server/auth/createLicenseRedirectCallback.js';
import validateLicense from '../../../lib/server/validateLicense.js';
import checkAuthorizedHost from '../../../lib/server/checkAuthorizedHost.js';
async function handler({ context, req, res }) {
if (authJson.configured !== true) {
@ -26,7 +28,12 @@ async function handler({ context, req, res }) {
return res.status(200).end();
}
if (req.url.startsWith('/api/auth/callback')) {
context.authOptions.callbacks.redirect = createLicenseRedirectCallback(context);
const license = await validateLicense(context);
const authorizedHost = checkAuthorizedHost({ license, req });
if (!authorizedHost) {
throw new Error('Domain not authorized to use license.');
}
context.authOptions.callbacks.redirect = createLicenseRedirectCallback(context, license);
} else {
context.authOptions.callbacks.redirect = context.authOptions.originalRedirectCallback;
}

View File

@ -19,6 +19,7 @@ async function handler({ context, req, res }) {
throw new Error('Only POST requests are supported.');
}
const { user, machine } = req.body;
const host = req.headers.host;
context.logger.info({ event: 'log_usage', user, machine });
const license = await validateLicense();
@ -29,7 +30,7 @@ async function handler({ context, req, res }) {
const data = [
`git_sha: ${appJson.git_sha}`,
`host: ${req.headers.host}`,
`host: ${host}`,
`license_key: ${license.id}`,
`machine: ${machine}`,
`timestamp: ${timestamp}`,
@ -45,7 +46,7 @@ async function handler({ context, req, res }) {
offline: false,
data: {
git_sha: appJson.git_sha,
host: req.headers.host,
host,
license_key: license.id,
machine,
sig,