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:amazon-page-navigation": "esno scripts/test-amazon-page-navigation.ts",
|
||||||
"test:execute-script": "esno scripts/test-execute-script.ts",
|
"test:execute-script": "esno scripts/test-execute-script.ts",
|
||||||
"test:extension-runtime": "node scripts/verify-extension-runtime.mjs",
|
"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"
|
"prepare": "husky"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"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 { onMessage } from 'webext-bridge/background';
|
||||||
import { flattenObject } from '~/logic/convert';
|
import { flattenObject } from '~/logic/convert';
|
||||||
import { exportKey, generateKeyPair, signData } from '~/logic/crypto';
|
import { exportKey, generateKeyPair, signData } from '~/logic/crypto';
|
||||||
import { remoteHost } from '~/env';
|
import { remoteBaseUrl } from '~/env';
|
||||||
import {
|
import {
|
||||||
AMAZON_SYNC_ALARM,
|
AMAZON_SYNC_ALARM,
|
||||||
AMAZON_SYNC_QUEUE_KEY,
|
AMAZON_SYNC_QUEUE_KEY,
|
||||||
@ -56,7 +56,7 @@ async function signedPost(path: string, data: unknown[]) {
|
|||||||
if (data.length === 0) return;
|
if (data.length === 0) return;
|
||||||
const body = JSON.stringify(data);
|
const body = JSON.stringify(data);
|
||||||
const { privateKey } = await keyPairPromise;
|
const { privateKey } = await keyPairPromise;
|
||||||
const response = await fetch(`https://${remoteHost}${path}`, {
|
const response = await fetch(`${remoteBaseUrl}${path}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { remoteHost } from '~/env';
|
import { remoteBaseUrl, remoteWebSocketBaseUrl } from '~/env';
|
||||||
import { useLongTask } from './useLongTask';
|
import { useLongTask } from './useLongTask';
|
||||||
|
|
||||||
type AddDataFragmentsCommand = {
|
type AddDataFragmentsCommand = {
|
||||||
@ -16,16 +16,12 @@ type WebSocketResponse =
|
|||||||
| { type: 'progress'; current: number; total: number }
|
| { type: 'progress'; current: number; total: number }
|
||||||
| { type: 'result'; result: string };
|
| { type: 'result'; result: string };
|
||||||
|
|
||||||
// 使用 wss:// 和 https://
|
|
||||||
const protocol = __DEV__ ? 'ws' : 'wss';
|
|
||||||
const httpProtocol = __DEV__ ? 'http' : 'https';
|
|
||||||
|
|
||||||
class ExportExcelPipeline {
|
class ExportExcelPipeline {
|
||||||
private socket: WebSocket;
|
private socket: WebSocket;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.socket = new WebSocket(
|
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.CLOSED:
|
||||||
case WebSocket.CLOSING:
|
case WebSocket.CLOSING:
|
||||||
this.socket = new WebSocket(
|
this.socket = new WebSocket(
|
||||||
`${protocol}://${remoteHost}/ws/daa0b9f1-4e4a-4e7c-9269-f5f0e86ae271`,
|
`${remoteWebSocketBaseUrl}/ws/daa0b9f1-4e4a-4e7c-9269-f5f0e86ae271`,
|
||||||
);
|
);
|
||||||
case WebSocket.CONNECTING:
|
case WebSocket.CONNECTING:
|
||||||
return new Promise<ExportExcelPipeline>((resolve) => {
|
return new Promise<ExportExcelPipeline>((resolve) => {
|
||||||
@ -126,7 +122,7 @@ export const useCloudExporter = () => {
|
|||||||
await pipeline.close();
|
await pipeline.close();
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
const url = `${httpProtocol}://${remoteHost}${file}`;
|
const url = `${remoteBaseUrl}${file}`;
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
link.href = url;
|
link.href = url;
|
||||||
link.download = `${dayjs().format('YYYY-MM-DD')}.xlsx`;
|
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 = [
|
const forbiddenProtocols = [
|
||||||
'chrome-extension://',
|
'chrome-extension://',
|
||||||
'chrome-search://',
|
'chrome-search://',
|
||||||
@ -14,6 +16,12 @@ export function isForbiddenUrl(url: string): boolean {
|
|||||||
|
|
||||||
export const isFirefox = navigator.userAgent.includes('Firefox');
|
export const isFirefox = navigator.userAgent.includes('Firefox');
|
||||||
|
|
||||||
export const remoteHost =
|
const remoteEndpoint = resolveRemoteEndpoint({
|
||||||
import.meta.env.VITE_REMOTE_HOST ||
|
isDev: __DEV__,
|
||||||
(__DEV__ ? '127.0.0.1:18000' : 'amzplugin.rekeymed.com');
|
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(
|
export async function uploadImage(
|
||||||
base64String: string,
|
base64String: string,
|
||||||
@ -23,8 +23,7 @@ export async function uploadImage(
|
|||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', blob, filename);
|
formData.append('file', blob, filename);
|
||||||
|
|
||||||
const httpProtocol = __DEV__ ? 'http' : 'https';
|
const url = `${remoteBaseUrl}/upload/image/${encodeURIComponent(filename)}`;
|
||||||
const url = `${httpProtocol}://${remoteHost}/upload/image/${encodeURIComponent(filename)}`;
|
|
||||||
const resp = (await fetch(url, {
|
const resp = (await fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData,
|
body: formData,
|
||||||
@ -33,5 +32,5 @@ export async function uploadImage(
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const data = await resp.json();
|
const data = await resp.json();
|
||||||
return `${httpProtocol}://${remoteHost}${data.file}`;
|
return `${remoteBaseUrl}${data.file}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { createAlova } from 'alova';
|
import { createAlova } from 'alova';
|
||||||
import adapterFetch from 'alova/fetch';
|
import adapterFetch from 'alova/fetch';
|
||||||
import { remoteHost } from '~/env';
|
import { remoteBaseUrl } from '~/env';
|
||||||
import VueHook from 'alova/vue';
|
import VueHook from 'alova/vue';
|
||||||
import { exportKey, generateKeyPair, signData } from '~/logic/crypto';
|
import { exportKey, generateKeyPair, signData } from '~/logic/crypto';
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ const keyPairPromise = generateKeyPair();
|
|||||||
const publicKeyBase64Promise = keyPairPromise.then(async ({ publicKey }) => exportKey(publicKey));
|
const publicKeyBase64Promise = keyPairPromise.then(async ({ publicKey }) => exportKey(publicKey));
|
||||||
|
|
||||||
const httpClient = createAlova({
|
const httpClient = createAlova({
|
||||||
baseURL: `${__DEV__ ? 'http' : 'https'}://${remoteHost}`,
|
baseURL: remoteBaseUrl,
|
||||||
requestAdapter: adapterFetch(),
|
requestAdapter: adapterFetch(),
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
statesHook: VueHook,
|
statesHook: VueHook,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user