chore(android): move release signing secrets to gitignored keystore.properties

This commit is contained in:
SkateSpots 2026-09-26 15:56:02 +07:00
parent 0ac57d4250
commit fc0231bea5
3 changed files with 102 additions and 3 deletions

1
.gitignore vendored
View file

@ -35,6 +35,7 @@ yarn.lock
# Local secrets & signing material (never commit)
*.jks
*.keystore
keystore.properties
local.properties
# Local build artifacts

View file

@ -9,11 +9,11 @@
"build": "npm i --silent && vite build -l error && cp dist/index.html dist/404.html && echo 'Project built successfully!'",
"test": "npm i --silent && tsc --noEmit && eslint && vitest run --reporter=dot --silent && vite build -l error && cp dist/index.html dist/404.html && echo 'All tests passed!'",
"deploy": "npm i --silent && npm run build && npx -y nostr-deploy-cli deploy --skip-setup",
"android:init": "npm run android:build:apk && npx cap add android && npx cap sync android && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs && node scripts/inject-network-security.mjs",
"android:sync": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs && node scripts/inject-network-security.mjs",
"android:init": "npm run android:build:apk && npx cap add android && npx cap sync android && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs && node scripts/inject-network-security.mjs && node scripts/inject-signing-config.mjs",
"android:sync": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs && node scripts/inject-network-security.mjs && node scripts/inject-signing-config.mjs",
"android:open": "npx cap open android",
"android:version": "node scripts/sync-android-version.mjs",
"android:build": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs && node scripts/inject-network-security.mjs && cd android && ./gradlew assembleRelease",
"android:build": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs && node scripts/inject-network-security.mjs && node scripts/inject-signing-config.mjs && cd android && ./gradlew assembleRelease",
"android:build:apk": "CAPACITOR_BUILD=1 vite build && sed -i 's|<script type=\"module\" src=\"/shakespeare_tailwind[^\"]*\\.js\"></script>||g' dist/index.html && sed -i 's|<style type=\"text/tailwindcss\">|<style>|g' dist/index.html && cp dist/index.html dist/404.html"
},
"dependencies": {

View file

@ -0,0 +1,98 @@
#!/usr/bin/env node
/**
* Inject the Android release signing configuration.
*
* WHY THIS EXISTS
* ───────────────
* The Android project (android/) is generated and NOT tracked in git —
* `npm run android:init` recreates it with `cap add android`. Release signing
* therefore has to be re-applied after every regeneration, and its secrets must
* never be committed. Previously the keystore path, alias and passwords were
* hardcoded inline in android/app/build.gradle.
*
* This script (idempotent, part of the android build, same pattern as the other
* scripts/inject-*.mjs helpers):
* 1. Removes any previously managed signing block.
* 2. Removes a legacy hardcoded signingConfigs block (inline passwords).
* 3. Writes a managed signingConfigs block into android/app/build.gradle that
* reads secrets from the gitignored keystore.properties at the repo root.
*
* It exits quietly (0) when android/ isn't generated yet, or when
* keystore.properties is absent — so debug-only builds without a keystore still
* work.
*/
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
const buildGradle = join(root, 'android', 'app', 'build.gradle');
const keystoreProps = join(root, 'keystore.properties');
const BEGIN = '// >>> managed by scripts/inject-signing-config.mjs';
const END = '// <<< managed by scripts/inject-signing-config.mjs <<<';
if (!existsSync(buildGradle)) {
console.log('[inject-signing-config] android/ not generated yet — skipping.');
process.exit(0);
}
if (!existsSync(keystoreProps)) {
console.log('[inject-signing-config] keystore.properties not found — skipping release signing.');
process.exit(0);
}
const managedLines = [
`${BEGIN} >>>`,
'// Release signing is read from keystore.properties at the repo root',
'// (gitignored). Edit that file, not this block.',
'def _keystoreProps = new Properties()',
"def _keystorePropsFile = rootProject.file('../keystore.properties')",
'if (_keystorePropsFile.exists()) {',
' _keystorePropsFile.withInputStream { _keystoreProps.load(it) }',
'}',
'signingConfigs {',
' release {',
' if (_keystorePropsFile.exists()) {',
" storeFile rootProject.file('../' + _keystoreProps['storeFile'])",
" storePassword _keystoreProps['storePassword']",
" keyAlias _keystoreProps['keyAlias']",
" keyPassword _keystoreProps['keyPassword']",
' }',
' }',
'}',
END,
];
const managed = managedLines.map((l) => ' ' + l).join('\n');
let src = readFileSync(buildGradle, 'utf8');
const before = src;
// 1. Drop any previously managed block so the script is idempotent.
const bIdx = src.indexOf(BEGIN);
if (bIdx !== -1) {
const eIdx = src.indexOf(END, bIdx);
if (eIdx !== -1) {
const lineStart = src.lastIndexOf('\n', bIdx);
const lineEnd = src.indexOf('\n', eIdx);
src = src.slice(0, lineStart) + (lineEnd === -1 ? '' : src.slice(lineEnd));
}
}
// 2. Drop a legacy hardcoded signingConfigs block (has an inline keyPassword).
src = src.replace(/\n[ \t]*signingConfigs\s*\{[\s\S]*?keyPassword\s+"[^"]*"\s*\}\s*\}/g, '');
// 3. Insert the managed block immediately after the `android {` opening.
const androidIdx = src.indexOf('android {');
if (androidIdx === -1) {
console.error('[inject-signing-config] could not find `android {` in build.gradle — aborting.');
process.exit(1);
}
const lineEnd = src.indexOf('\n', androidIdx);
src = src.slice(0, lineEnd + 1) + managed + '\n' + src.slice(lineEnd + 1);
if (src === before) {
console.log('[inject-signing-config] already up to date.');
} else {
writeFileSync(buildGradle, src);
console.log('[inject-signing-config] ✓ Wrote managed release signing config into android/app/build.gradle.');
}