feat(plugins): move game resources behind marketplace
This commit is contained in:
@@ -1,14 +1,11 @@
|
||||
const { execFileSync } = require('child_process');
|
||||
const { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } = require('fs');
|
||||
const { cpSync, existsSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } = require('fs');
|
||||
const { join } = require('path');
|
||||
|
||||
const MEOWA_RELEASE_CREDENTIAL_FILE_NAME = 'meowa-game-assets-credential.json';
|
||||
|
||||
exports.default = async function afterPack(context) {
|
||||
const platform = context.electronPlatformName;
|
||||
console.log(`[after-pack] Target: ${platform}/${context.arch}`);
|
||||
|
||||
writeMeowaReleaseCredential(context);
|
||||
copyPublishRuntime(context);
|
||||
assertNoPersistedUserData(context.appOutDir);
|
||||
|
||||
@@ -32,25 +29,6 @@ function copyPublishRuntime(context) {
|
||||
console.log('[after-pack] Copied self-contained npm publish runtime.');
|
||||
}
|
||||
|
||||
function writeMeowaReleaseCredential(context) {
|
||||
const apiKey = process.env.MEOWART_API_KEY?.trim();
|
||||
if (!apiKey) {
|
||||
console.log('[after-pack] Meowa release credential not included; MEOWART_API_KEY is unset.');
|
||||
return false;
|
||||
}
|
||||
|
||||
const resourcesDir = context.packager.getResourcesDir(context.appOutDir);
|
||||
const target = join(resourcesDir, 'resources', MEOWA_RELEASE_CREDENTIAL_FILE_NAME);
|
||||
mkdirSync(join(resourcesDir, 'resources'), { recursive: true });
|
||||
writeFileSync(
|
||||
target,
|
||||
`${JSON.stringify({ schemaVersion: 1, apiKey })}\n`,
|
||||
{ encoding: 'utf8', mode: 0o600 },
|
||||
);
|
||||
console.log('[after-pack] Meowa release credential included in packaged Main resources.');
|
||||
return true;
|
||||
}
|
||||
|
||||
const PERSISTED_USER_DATA_FILES = new Set([
|
||||
'gateway-prelaunch-maintenance-cache.json',
|
||||
'niancode-device-identity.json',
|
||||
@@ -227,4 +205,3 @@ function patchNsisExtractionMacro() {
|
||||
}
|
||||
|
||||
exports.assertNoPersistedUserData = assertNoPersistedUserData;
|
||||
exports.writeMeowaReleaseCredential = writeMeowaReleaseCredential;
|
||||
|
||||
@@ -37,9 +37,14 @@ const MARKETPLACE_ARTIFACT_MARKERS = Object.freeze({
|
||||
packageTrust: Object.freeze([
|
||||
'makelore-plugin-release.v1',
|
||||
'skill_only',
|
||||
'platform_hosted',
|
||||
'plugin_signature_invalid',
|
||||
'signing key is not trusted',
|
||||
]),
|
||||
hostedRuntime: Object.freeze([
|
||||
'makelore.game-resource',
|
||||
'/api/plugins/v1/hosted/game-resource/generations',
|
||||
]),
|
||||
mainRoutes: Object.freeze([
|
||||
'/api/coding/plugin-marketplace',
|
||||
'plugin-marketplace\\/install\\/',
|
||||
@@ -56,6 +61,13 @@ const MARKETPLACE_ARTIFACT_MARKERS = Object.freeze({
|
||||
'我的插件',
|
||||
]),
|
||||
});
|
||||
const FORBIDDEN_MEOWA_ARTIFACT_MARKERS = Object.freeze([
|
||||
'MEOWA_API_KEY',
|
||||
'MEOWA_API_URL',
|
||||
'MEOWA_GAME_ASSETS_SHARED_SECRET',
|
||||
'/api/coding/meowa-game-assets',
|
||||
'https://api.meowa.ai',
|
||||
]);
|
||||
const CODE_OWNED_PLUGIN_SIGNING_KEYS_SOURCE_MARKER = 'makelore.plugin-trust.code-owned.v1';
|
||||
const PI_AI_PROVIDER_PREFIX = 'pi-runtime/node_modules/@earendil-works/pi-ai/dist/providers/';
|
||||
const PI_AI_PROVIDER_ASAR_PREFIX = 'app.asar/node_modules/@earendil-works/pi-ai/dist/providers/';
|
||||
@@ -297,6 +309,12 @@ export function verifyMarketplaceClientArtifact(appAsarContents, productionTrust
|
||||
if (missing.length > 0) {
|
||||
throw new Error(`Packaged app.asar does not contain Marketplace contract markers: ${missing.join(', ')}`);
|
||||
}
|
||||
const forbidden = FORBIDDEN_MEOWA_ARTIFACT_MARKERS.filter((marker) => (
|
||||
appAsarContents.includes(Buffer.from(marker))
|
||||
));
|
||||
if (forbidden.length > 0) {
|
||||
throw new Error(`Packaged app.asar still contains legacy Meowa client authority: ${forbidden.join(', ')}`);
|
||||
}
|
||||
const hasEmptyCodeOwnedTrust = /(?:CODE_OWNED_PLUGIN_SIGNING_KEYS\s*=\s*)?Object\.freeze\(\s*\{\}\s*(?:as\s+[^)]*)?\)/u.test(productionTrustSource);
|
||||
if (!hasEmptyCodeOwnedTrust
|
||||
|| !productionTrustSource.includes(CODE_OWNED_PLUGIN_SIGNING_KEYS_SOURCE_MARKER)
|
||||
@@ -307,6 +325,8 @@ export function verifyMarketplaceClientArtifact(appAsarContents, productionTrust
|
||||
}
|
||||
return {
|
||||
schema2SkillOnly: true,
|
||||
schema2PlatformHosted: true,
|
||||
legacyMeowaClientAuthorityAbsent: true,
|
||||
productionTrust: 'official-key-absent-fail-closed',
|
||||
libraryInstallAndEffectiveRoutes: true,
|
||||
rendererAssets: true,
|
||||
|
||||
@@ -11,14 +11,6 @@ const ELECTRON_BUILDER_BIN = process.platform === 'win32'
|
||||
: path.join(ROOT, 'node_modules', '.bin', 'electron-builder');
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const publishingRelease = args.some((arg, index) => arg === '--publish' && args[index + 1] === 'always')
|
||||
|| args.includes('--publish=always');
|
||||
const releaseCredentialRequired = publishingRelease || process.env.MEOWA_RELEASE_KEY_REQUIRED === '1';
|
||||
if (releaseCredentialRequired && !process.env.MEOWART_API_KEY?.trim()) {
|
||||
console.error('[release] MEOWART_API_KEY is required for a Meowa-enabled release build.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function shellQuote(value) {
|
||||
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user