mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-08-05 06:50:10 +00:00
fix: align fill assist compatibility
This commit is contained in:
@@ -1,19 +1,46 @@
|
|||||||
const EMPTY_FORMS_FILENAME = 'forms.v1.json';
|
const EMPTY_FORMS_FILENAME = 'forms.v1.json';
|
||||||
|
const EMPTY_FORMS_SCHEMA_FILENAME = 'forms.v1.schema.json';
|
||||||
|
const EMPTY_FORMS_CID = 'sha256:189fa7c9bcf8951e65c18b5d9feacf74a5223c75e01667c4235388cbc67091fe';
|
||||||
|
|
||||||
const EMPTY_FORMS_BODY = JSON.stringify({
|
const EMPTY_FORMS_BODY = JSON.stringify({
|
||||||
schemaVersion: '1.0.0',
|
schemaVersion: '1.0.0',
|
||||||
hosts: {},
|
hosts: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const EMPTY_FORMS_SCHEMA_BODY = JSON.stringify({
|
||||||
|
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
||||||
|
title: 'Bitwarden Fill Assist Forms v1',
|
||||||
|
type: 'object',
|
||||||
|
required: ['schemaVersion', 'hosts'],
|
||||||
|
properties: {
|
||||||
|
schemaVersion: { type: 'string' },
|
||||||
|
hosts: { type: 'object' },
|
||||||
|
},
|
||||||
|
additionalProperties: true,
|
||||||
|
});
|
||||||
|
|
||||||
const EMPTY_MANIFEST_BODY = JSON.stringify({
|
const EMPTY_MANIFEST_BODY = JSON.stringify({
|
||||||
|
buildId: 'nodewarden-empty-fill-assist-v1',
|
||||||
|
timestamp: '2026-07-06T00:00:00.000Z',
|
||||||
|
gitSha: 'nodewarden',
|
||||||
maps: {
|
maps: {
|
||||||
forms: {
|
forms: {
|
||||||
v1: {
|
v1: {
|
||||||
filename: EMPTY_FORMS_FILENAME,
|
filename: EMPTY_FORMS_FILENAME,
|
||||||
cid: 'sha256:nodewarden-empty-fill-assist-v1',
|
cid: EMPTY_FORMS_CID,
|
||||||
|
schema: EMPTY_FORMS_SCHEMA_FILENAME,
|
||||||
|
deprecated: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const DIGITAL_ASSET_LINK_CHECK_BODY = JSON.stringify({
|
||||||
|
linked: false,
|
||||||
|
maxAge: '86400s',
|
||||||
|
debugString: 'No matching digital asset link policy is configured for this server.',
|
||||||
|
});
|
||||||
|
|
||||||
function fillAssistJsonResponse(body: string): Response {
|
function fillAssistJsonResponse(body: string): Response {
|
||||||
return new Response(body, {
|
return new Response(body, {
|
||||||
status: 200,
|
status: 200,
|
||||||
@@ -24,13 +51,30 @@ function fillAssistJsonResponse(body: string): Response {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeFilename(filename: string): string {
|
||||||
|
const raw = String(filename || '').trim();
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(raw);
|
||||||
|
} catch {
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function handleFillAssistManifest(): Response {
|
export function handleFillAssistManifest(): Response {
|
||||||
return fillAssistJsonResponse(EMPTY_MANIFEST_BODY);
|
return fillAssistJsonResponse(EMPTY_MANIFEST_BODY);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleFillAssistForms(filename: string): Response {
|
export function handleFillAssistForms(filename: string): Response {
|
||||||
if (String(filename || '').trim() !== EMPTY_FORMS_FILENAME) {
|
const normalized = normalizeFilename(filename);
|
||||||
return new Response('Not found', { status: 404 });
|
if (normalized === EMPTY_FORMS_FILENAME) {
|
||||||
}
|
|
||||||
return fillAssistJsonResponse(EMPTY_FORMS_BODY);
|
return fillAssistJsonResponse(EMPTY_FORMS_BODY);
|
||||||
}
|
}
|
||||||
|
if (normalized === EMPTY_FORMS_SCHEMA_FILENAME) {
|
||||||
|
return fillAssistJsonResponse(EMPTY_FORMS_SCHEMA_BODY);
|
||||||
|
}
|
||||||
|
return new Response('Not found', { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function handleDigitalAssetLinkCheck(): Response {
|
||||||
|
return fillAssistJsonResponse(DIGITAL_ASSET_LINK_CHECK_BODY);
|
||||||
|
}
|
||||||
|
|||||||
+12
-2
@@ -7,7 +7,11 @@ import {
|
|||||||
handleDownloadSendFile,
|
handleDownloadSendFile,
|
||||||
} from './handlers/sends';
|
} from './handlers/sends';
|
||||||
import { handleKnownDevice } from './handlers/devices';
|
import { handleKnownDevice } from './handlers/devices';
|
||||||
import { handleFillAssistForms, handleFillAssistManifest } from './handlers/fill-assist';
|
import {
|
||||||
|
handleDigitalAssetLinkCheck,
|
||||||
|
handleFillAssistForms,
|
||||||
|
handleFillAssistManifest,
|
||||||
|
} from './handlers/fill-assist';
|
||||||
import { handleToken, handlePrelogin, handleRevocation } from './handlers/identity';
|
import { handleToken, handlePrelogin, handleRevocation } from './handlers/identity';
|
||||||
import { handleGetAccountPasskeyAssertionOptions } from './handlers/account-passkeys';
|
import { handleGetAccountPasskeyAssertionOptions } from './handlers/account-passkeys';
|
||||||
import {
|
import {
|
||||||
@@ -97,7 +101,7 @@ function buildIconServiceCsp(origin: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildConfigResponse(origin: string) {
|
function buildConfigResponse(origin: string) {
|
||||||
const fillAssistBase = `${origin}/fill-assist`;
|
const fillAssistBase = `${origin}/fill-assist/`;
|
||||||
return {
|
return {
|
||||||
version: LIMITS.compatibility.bitwardenServerVersion,
|
version: LIMITS.compatibility.bitwardenServerVersion,
|
||||||
gitHash: 'nodewarden',
|
gitHash: 'nodewarden',
|
||||||
@@ -350,6 +354,12 @@ export async function handlePublicRoute(
|
|||||||
return handleFillAssistManifest();
|
return handleFillAssistManifest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((path === '/v1/assetlinks:check' || path === '/api/v1/assetlinks:check') && method === 'GET') {
|
||||||
|
const blocked = await enforcePublicRateLimit('public-read', LIMITS.rateLimit.publicReadRequestsPerMinute);
|
||||||
|
if (blocked) return blocked;
|
||||||
|
return handleDigitalAssetLinkCheck();
|
||||||
|
}
|
||||||
|
|
||||||
const fillAssistFormsMatch = path.match(/^\/fill-assist\/([^/]+)$/i);
|
const fillAssistFormsMatch = path.match(/^\/fill-assist\/([^/]+)$/i);
|
||||||
if (fillAssistFormsMatch && method === 'GET') {
|
if (fillAssistFormsMatch && method === 'GET') {
|
||||||
const blocked = await enforcePublicRateLimit('public-read', LIMITS.rateLimit.publicReadRequestsPerMinute);
|
const blocked = await enforcePublicRateLimit('public-read', LIMITS.rateLimit.publicReadRequestsPerMinute);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ function canServeWithUnsafeJwtSecret(path: string, method: string): boolean {
|
|||||||
if (method === 'GET' && path === '/.well-known/appspecific/com.chrome.devtools.json') return true;
|
if (method === 'GET' && path === '/.well-known/appspecific/com.chrome.devtools.json') return true;
|
||||||
if (method === 'GET' && path === '/fill-assist/manifest.json') return true;
|
if (method === 'GET' && path === '/fill-assist/manifest.json') return true;
|
||||||
if (method === 'GET' && /^\/fill-assist\/[^/]+$/i.test(path)) return true;
|
if (method === 'GET' && /^\/fill-assist\/[^/]+$/i.test(path)) return true;
|
||||||
|
if (method === 'GET' && (path === '/v1/assetlinks:check' || path === '/api/v1/assetlinks:check')) return true;
|
||||||
if (method === 'GET' && /^\/icons\/[^/]+\/icon\.png$/i.test(path)) return true;
|
if (method === 'GET' && /^\/icons\/[^/]+\/icon\.png$/i.test(path)) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ function isExtensionOrigin(origin: string): boolean {
|
|||||||
function isWildcardCorsPath(path: string): boolean {
|
function isWildcardCorsPath(path: string): boolean {
|
||||||
return (
|
return (
|
||||||
path.startsWith('/icons/')
|
path.startsWith('/icons/')
|
||||||
|
|| path.startsWith('/fill-assist/')
|
||||||
|
|| path === '/v1/assetlinks:check'
|
||||||
|
|| path === '/api/v1/assetlinks:check'
|
||||||
|| path === '/config'
|
|| path === '/config'
|
||||||
|| path === '/api/config'
|
|| path === '/api/config'
|
||||||
|| path === '/api/version'
|
|| path === '/api/version'
|
||||||
|
|||||||
Reference in New Issue
Block a user