mirror of
https://github.com/primedigitaltech/azon_seeker.git
synced 2026-10-05 07:13:06 +08:00
fix: route extension sync through configured server
This commit is contained in:
parent
bcbdc321c8
commit
d98b672b2e
@ -32,6 +32,8 @@
|
||||
"test:amazon-page-navigation": "esno scripts/test-amazon-page-navigation.ts",
|
||||
"test:execute-script": "esno scripts/test-execute-script.ts",
|
||||
"test:extension-runtime": "node scripts/verify-extension-runtime.mjs",
|
||||
"test:remote-endpoint": "esno scripts/test-remote-endpoint.ts",
|
||||
"test:production-endpoint": "node scripts/verify-production-endpoint.mjs",
|
||||
"prepare": "husky"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
34
scripts/test-remote-endpoint.ts
Normal file
34
scripts/test-remote-endpoint.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { resolveRemoteEndpoint } from '../src/logic/remote-endpoint';
|
||||
|
||||
assert.deepEqual(resolveRemoteEndpoint({ isDev: true }), {
|
||||
host: '127.0.0.1:18000',
|
||||
httpBaseUrl: 'http://127.0.0.1:18000',
|
||||
webSocketBaseUrl: 'ws://127.0.0.1:18000',
|
||||
});
|
||||
|
||||
assert.deepEqual(resolveRemoteEndpoint({ isDev: false }), {
|
||||
host: 'amzplugin.rekeymed.com',
|
||||
httpBaseUrl: 'https://amzplugin.rekeymed.com',
|
||||
webSocketBaseUrl: 'wss://amzplugin.rekeymed.com',
|
||||
});
|
||||
|
||||
assert.deepEqual(
|
||||
resolveRemoteEndpoint({
|
||||
isDev: true,
|
||||
host: 'staging.example.test:8443',
|
||||
protocol: 'https',
|
||||
}),
|
||||
{
|
||||
host: 'staging.example.test:8443',
|
||||
httpBaseUrl: 'https://staging.example.test:8443',
|
||||
webSocketBaseUrl: 'wss://staging.example.test:8443',
|
||||
},
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => resolveRemoteEndpoint({ isDev: true, protocol: 'ftp' }),
|
||||
/Unsupported remote protocol/,
|
||||
);
|
||||
|
||||
console.log('Remote endpoint tests passed.');
|
||||
29
scripts/verify-production-endpoint.mjs
Normal file
29
scripts/verify-production-endpoint.mjs
Normal file
@ -0,0 +1,29 @@
|
||||
import { readdir, readFile } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
|
||||
const background = await readFile('extension/dist/background/index.mjs', 'utf8');
|
||||
async function readJavaScriptFiles(directory) {
|
||||
const entries = await readdir(directory, { withFileTypes: true });
|
||||
const contents = await Promise.all(
|
||||
entries.map(async (entry) => {
|
||||
const path = join(directory, entry.name);
|
||||
if (entry.isDirectory()) return readJavaScriptFiles(path);
|
||||
if (!/\.(?:m?js)$/.test(entry.name)) return '';
|
||||
return readFile(path, 'utf8');
|
||||
}),
|
||||
);
|
||||
return contents.flat().join('\n');
|
||||
}
|
||||
const allJavaScript = await readJavaScriptFiles('extension/dist');
|
||||
|
||||
if (!background.includes('amzplugin.rekeymed.com')) {
|
||||
throw new Error('Production background bundle does not target the public server.');
|
||||
}
|
||||
if (background.includes('127.0.0.1:18000')) {
|
||||
throw new Error('Production background bundle still contains the local API endpoint.');
|
||||
}
|
||||
if (!allJavaScript.includes('wss://') || !background.includes('https://')) {
|
||||
throw new Error('Production bundle is missing secure HTTP/WebSocket protocols.');
|
||||
}
|
||||
|
||||
console.log('Production endpoint verification passed.');
|
||||
@ -1,7 +1,7 @@
|
||||
import { onMessage } from 'webext-bridge/background';
|
||||
import { flattenObject } from '~/logic/convert';
|
||||
import { exportKey, generateKeyPair, signData } from '~/logic/crypto';
|
||||
import { remoteHost } from '~/env';
|
||||
import { remoteBaseUrl } from '~/env';
|
||||
import {
|
||||
AMAZON_SYNC_ALARM,
|
||||
AMAZON_SYNC_QUEUE_KEY,
|
||||
@ -56,7 +56,7 @@ async function signedPost(path: string, data: unknown[]) {
|
||||
if (data.length === 0) return;
|
||||
const body = JSON.stringify(data);
|
||||
const { privateKey } = await keyPairPromise;
|
||||
const response = await fetch(`https://${remoteHost}${path}`, {
|
||||
const response = await fetch(`${remoteBaseUrl}${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { remoteHost } from '~/env';
|
||||
import { remoteBaseUrl, remoteWebSocketBaseUrl } from '~/env';
|
||||
import { useLongTask } from './useLongTask';
|
||||
|
||||
type AddDataFragmentsCommand = {
|
||||
@ -16,16 +16,12 @@ type WebSocketResponse =
|
||||
| { type: 'progress'; current: number; total: number }
|
||||
| { type: 'result'; result: string };
|
||||
|
||||
// 使用 wss:// 和 https://
|
||||
const protocol = __DEV__ ? 'ws' : 'wss';
|
||||
const httpProtocol = __DEV__ ? 'http' : 'https';
|
||||
|
||||
class ExportExcelPipeline {
|
||||
private socket: WebSocket;
|
||||
|
||||
constructor() {
|
||||
this.socket = new WebSocket(
|
||||
`${protocol}://${remoteHost}/ws/daa0b9f1-4e4a-4e7c-9269-f5f0e86ae271`,
|
||||
`${remoteWebSocketBaseUrl}/ws/daa0b9f1-4e4a-4e7c-9269-f5f0e86ae271`,
|
||||
);
|
||||
}
|
||||
|
||||
@ -39,7 +35,7 @@ class ExportExcelPipeline {
|
||||
case WebSocket.CLOSED:
|
||||
case WebSocket.CLOSING:
|
||||
this.socket = new WebSocket(
|
||||
`${protocol}://${remoteHost}/ws/daa0b9f1-4e4a-4e7c-9269-f5f0e86ae271`,
|
||||
`${remoteWebSocketBaseUrl}/ws/daa0b9f1-4e4a-4e7c-9269-f5f0e86ae271`,
|
||||
);
|
||||
case WebSocket.CONNECTING:
|
||||
return new Promise<ExportExcelPipeline>((resolve) => {
|
||||
@ -126,7 +122,7 @@ export const useCloudExporter = () => {
|
||||
await pipeline.close();
|
||||
|
||||
if (file) {
|
||||
const url = `${httpProtocol}://${remoteHost}${file}`;
|
||||
const url = `${remoteBaseUrl}${file}`;
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `${dayjs().format('YYYY-MM-DD')}.xlsx`;
|
||||
|
||||
14
src/env.ts
14
src/env.ts
@ -1,3 +1,5 @@
|
||||
import { resolveRemoteEndpoint } from '~/logic/remote-endpoint';
|
||||
|
||||
const forbiddenProtocols = [
|
||||
'chrome-extension://',
|
||||
'chrome-search://',
|
||||
@ -14,6 +16,12 @@ export function isForbiddenUrl(url: string): boolean {
|
||||
|
||||
export const isFirefox = navigator.userAgent.includes('Firefox');
|
||||
|
||||
export const remoteHost =
|
||||
import.meta.env.VITE_REMOTE_HOST ||
|
||||
(__DEV__ ? '127.0.0.1:18000' : 'amzplugin.rekeymed.com');
|
||||
const remoteEndpoint = resolveRemoteEndpoint({
|
||||
isDev: __DEV__,
|
||||
host: import.meta.env.VITE_REMOTE_HOST,
|
||||
protocol: import.meta.env.VITE_REMOTE_PROTOCOL,
|
||||
});
|
||||
|
||||
export const remoteHost = remoteEndpoint.host;
|
||||
export const remoteBaseUrl = remoteEndpoint.httpBaseUrl;
|
||||
export const remoteWebSocketBaseUrl = remoteEndpoint.webSocketBaseUrl;
|
||||
|
||||
28
src/logic/remote-endpoint.ts
Normal file
28
src/logic/remote-endpoint.ts
Normal file
@ -0,0 +1,28 @@
|
||||
type RemoteEndpointOptions = {
|
||||
isDev: boolean;
|
||||
host?: string;
|
||||
protocol?: string;
|
||||
};
|
||||
|
||||
export type RemoteEndpoint = {
|
||||
host: string;
|
||||
httpBaseUrl: string;
|
||||
webSocketBaseUrl: string;
|
||||
};
|
||||
|
||||
export function resolveRemoteEndpoint({
|
||||
isDev,
|
||||
host,
|
||||
protocol,
|
||||
}: RemoteEndpointOptions): RemoteEndpoint {
|
||||
const resolvedHost = host || (isDev ? '127.0.0.1:18000' : 'amzplugin.rekeymed.com');
|
||||
const resolvedProtocol = protocol || (isDev ? 'http' : 'https');
|
||||
if (resolvedProtocol !== 'http' && resolvedProtocol !== 'https') {
|
||||
throw new Error(`Unsupported remote protocol: ${resolvedProtocol}`);
|
||||
}
|
||||
return {
|
||||
host: resolvedHost,
|
||||
httpBaseUrl: `${resolvedProtocol}://${resolvedHost}`,
|
||||
webSocketBaseUrl: `${resolvedProtocol === 'https' ? 'wss' : 'ws'}://${resolvedHost}`,
|
||||
};
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/** 上传图片工具类 */
|
||||
import { remoteHost } from '~/env';
|
||||
import { remoteBaseUrl } from '~/env';
|
||||
|
||||
export async function uploadImage(
|
||||
base64String: string,
|
||||
@ -23,8 +23,7 @@ export async function uploadImage(
|
||||
const formData = new FormData();
|
||||
formData.append('file', blob, filename);
|
||||
|
||||
const httpProtocol = __DEV__ ? 'http' : 'https';
|
||||
const url = `${httpProtocol}://${remoteHost}/upload/image/${encodeURIComponent(filename)}`;
|
||||
const url = `${remoteBaseUrl}/upload/image/${encodeURIComponent(filename)}`;
|
||||
const resp = (await fetch(url, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
@ -33,5 +32,5 @@ export async function uploadImage(
|
||||
return undefined;
|
||||
}
|
||||
const data = await resp.json();
|
||||
return `${httpProtocol}://${remoteHost}${data.file}`;
|
||||
return `${remoteBaseUrl}${data.file}`;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { createAlova } from 'alova';
|
||||
import adapterFetch from 'alova/fetch';
|
||||
import { remoteHost } from '~/env';
|
||||
import { remoteBaseUrl } from '~/env';
|
||||
import VueHook from 'alova/vue';
|
||||
import { exportKey, generateKeyPair, signData } from '~/logic/crypto';
|
||||
|
||||
@ -8,7 +8,7 @@ const keyPairPromise = generateKeyPair();
|
||||
const publicKeyBase64Promise = keyPairPromise.then(async ({ publicKey }) => exportKey(publicKey));
|
||||
|
||||
const httpClient = createAlova({
|
||||
baseURL: `${__DEV__ ? 'http' : 'https'}://${remoteHost}`,
|
||||
baseURL: remoteBaseUrl,
|
||||
requestAdapter: adapterFetch(),
|
||||
timeout: 10000,
|
||||
statesHook: VueHook,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user