9f42ee2460
Private, offline speech-to-text that runs Whisper on the user's own device — free, no account, no per-minute fees. Replaces Otter.ai / Rev. - Pure, tested engine: chunking, overlap timestamp-stitching, exports (SRT/VTT/TXT/MD/JSON), WAV codec, resampler, job queue, model catalog (142 tests). - Platform-abstracted TranscriptionEngine: transformers.js on web (loaded from CDN at runtime to dodge Metro's onnxruntime-web bundling limits), whisper.rn on native. Shared pipeline orchestrates decode -> chunk -> transcribe -> stitch. - Cross-platform StorageRepo (Dexie web / expo-sqlite native), Zod-validated. - UI: library + search, import, live-progress transcription, synced click-to-seek editor, multi-format export; model picker + privacy in settings. - Web ships as a single-page PWA with COOP/COEP isolation for threaded WASM; Docker (nginx) image + Traefik compose for wisp.briggen.dev. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
121 lines
5.2 KiB
Bash
Executable File
121 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# scripts/gen-keystore.sh
|
|
# ---------------------------------------------------------------------------
|
|
# Generate a NEW dedicated release keystore for Wisp, then print the exact
|
|
# commands to base64-encode it and the list of Gitea Actions secrets to set.
|
|
#
|
|
# Run this ONCE on a trusted machine. The resulting keystore is the SINGLE
|
|
# source of truth for signing every future Wisp APK — if you lose it (or its
|
|
# passwords), you cannot ship an update that upgrades an already-installed APK
|
|
# (signature mismatch). BACK IT UP somewhere safe (password manager / offline).
|
|
#
|
|
# This script does NOT touch CI, does NOT commit anything, and does NOT generate
|
|
# a "real" production key for you silently — YOU run it, YOU keep the output.
|
|
#
|
|
# Requires: keytool (ships with any JDK).
|
|
#
|
|
# Usage:
|
|
# ./scripts/gen-keystore.sh # interactive password prompts
|
|
# STORE_PASS=... KEY_PASS=... ./scripts/gen-keystore.sh # non-interactive
|
|
# ---------------------------------------------------------------------------
|
|
|
|
set -euo pipefail
|
|
|
|
# --- Tunables (override via env) --------------------------------------------
|
|
# Output keystore path. Default lands beside the script, OUTSIDE the app tree so
|
|
# you don't accidentally commit it (.gitignore already excludes *.jks/*.keystore,
|
|
# but we keep it out of the way regardless).
|
|
KEYSTORE_OUT="${KEYSTORE_OUT:-./wisp-release.keystore}"
|
|
# Key alias. MUST match ANDROID_KEY_ALIAS in CI. scripts/ci-android-sign.sh and
|
|
# the docs assume the alias 'wisp'.
|
|
KEY_ALIAS="${KEY_ALIAS:-wisp}"
|
|
# RSA 2048, valid for 10000 days (~27 years) — Google Play's minimum validity
|
|
# recommendation for upload/app-signing keys is well within this.
|
|
KEY_ALG="RSA"
|
|
KEY_SIZE="2048"
|
|
VALIDITY_DAYS="10000"
|
|
# Distinguished Name. Edit to taste; only CN is really meaningful for an app key.
|
|
DNAME="${DNAME:-CN=Wisp, OU=Wisp, O=briggen.dev, L=, ST=, C=DE}"
|
|
|
|
log() { printf '[gen-keystore] %s\n' "$*"; }
|
|
fail() { printf '[gen-keystore] ERROR: %s\n' "$*" >&2; exit 1; }
|
|
|
|
# --- Preconditions ----------------------------------------------------------
|
|
command -v keytool >/dev/null 2>&1 || fail "keytool not found. Install a JDK (e.g. JDK 17)."
|
|
|
|
if [[ -e "${KEYSTORE_OUT}" ]]; then
|
|
fail "Refusing to overwrite existing keystore at ${KEYSTORE_OUT}. Move/delete it first."
|
|
fi
|
|
|
|
# --- Collect passwords ------------------------------------------------------
|
|
# Allow non-interactive use via env (STORE_PASS / KEY_PASS); otherwise prompt.
|
|
# We do NOT echo passwords. For most setups STORE_PASS and KEY_PASS can be equal.
|
|
STORE_PASS="${STORE_PASS:-}"
|
|
KEY_PASS="${KEY_PASS:-}"
|
|
|
|
if [[ -z "${STORE_PASS}" ]]; then
|
|
read -r -s -p "Enter NEW keystore (store) password: " STORE_PASS; echo
|
|
read -r -s -p "Confirm keystore password: " STORE_PASS_CONFIRM; echo
|
|
[[ "${STORE_PASS}" == "${STORE_PASS_CONFIRM}" ]] || fail "Store passwords do not match."
|
|
fi
|
|
[[ "${#STORE_PASS}" -ge 6 ]] || fail "Keystore password must be at least 6 characters (keytool requirement)."
|
|
|
|
if [[ -z "${KEY_PASS}" ]]; then
|
|
read -r -s -p "Enter NEW key (alias) password [blank = same as store]: " KEY_PASS; echo
|
|
KEY_PASS="${KEY_PASS:-$STORE_PASS}"
|
|
fi
|
|
|
|
# --- Generate the keystore --------------------------------------------------
|
|
# -storetype PKCS12 is the modern default (JKS is deprecated). keytool will emit
|
|
# a PKCS12 keystore; that's fully supported by Gradle/apksigner.
|
|
log "Generating ${KEY_ALG} ${KEY_SIZE} key, alias '${KEY_ALIAS}', valid ${VALIDITY_DAYS} days..."
|
|
keytool -genkeypair \
|
|
-keystore "${KEYSTORE_OUT}" \
|
|
-storetype PKCS12 \
|
|
-alias "${KEY_ALIAS}" \
|
|
-keyalg "${KEY_ALG}" \
|
|
-keysize "${KEY_SIZE}" \
|
|
-validity "${VALIDITY_DAYS}" \
|
|
-dname "${DNAME}" \
|
|
-storepass "${STORE_PASS}" \
|
|
-keypass "${KEY_PASS}"
|
|
|
|
log "Keystore created: ${KEYSTORE_OUT}"
|
|
echo
|
|
|
|
# --- Print follow-up instructions -------------------------------------------
|
|
# Show the EXACT base64 command and the secrets to configure in Gitea. We print
|
|
# the base64 command (not the base64 itself, and never the passwords) so the
|
|
# human runs it themselves and pastes into the Gitea secrets UI.
|
|
cat <<EOF
|
|
=============================================================================
|
|
NEXT STEPS — configure Gitea Actions secrets for the build-apk job
|
|
=============================================================================
|
|
|
|
1) Base64-encode the keystore (single line, no wrapping) and copy it:
|
|
|
|
# Linux:
|
|
base64 -w0 "${KEYSTORE_OUT}"
|
|
|
|
# macOS (no -w flag; -b0 disables wrapping):
|
|
base64 -b0 "${KEYSTORE_OUT}"
|
|
|
|
Copy the entire single-line output — that is ANDROID_KEYSTORE_BASE64.
|
|
|
|
2) In Gitea -> the Wisp repo -> Settings -> Actions -> Secrets, add:
|
|
|
|
ANDROID_KEYSTORE_BASE64 = <the base64 string from step 1>
|
|
ANDROID_KEYSTORE_PASSWORD = <the store password you just chose>
|
|
ANDROID_KEY_ALIAS = ${KEY_ALIAS}
|
|
ANDROID_KEY_PASSWORD = <the key password you just chose>
|
|
|
|
(These names match scripts/ci-android-sign.sh and .gitea/workflows/ci.yml.)
|
|
|
|
3) BACK UP "${KEYSTORE_OUT}" and BOTH passwords in a safe place (password
|
|
manager / offline). If lost, you can never update an already-installed APK.
|
|
|
|
4) Do NOT commit the keystore. (.gitignore already excludes *.keystore/*.jks.)
|
|
=============================================================================
|
|
EOF
|