Files
HomeDash/deploy/sign-firefox.sh
JianFeeeee e9097e5893 feat(icon): 纸飞机图标(站点 favicon + 扩展各尺寸)
站点首页此前显示的是 Dashy 上游的 logo —— index.html 里那几条
<link rel=icon href=/web-icons/favicon-*.png> 优先级高于我们的门户图标,
而扩展的 PNG 是占位图(128px 只有 9 种颜色、alpha 通道还是乱的)。

- portal/favicon.svg:纸飞机(圆角渐变底 + 白色折纸机头朝右上 + 两道尾迹),
  几何收在 8..56 安全区,避免贴边被圆角裁切
- 由该 SVG 派生 favicon.ico(16/32/48)、apple-touch-icon(180)、
  web-icons/favicon-{16,32,64}、扩展 icon{16,48,96,128}
- patch-index.py:删掉上游 icon link 并显式指向 /favicon.svg(幂等,
  重复执行 unchanged);上游 web-icons 那批也覆盖一份作双保险
- Dockerfile 与 zd-host.sh 都 COPY 这些图标进镜像
- 验证:nginx 沙箱实测 /favicon.svg、/web-icons/*、/apple-touch-icon.png 均 200;
  16px 下人眼仍可辨识为纸飞机
- .amo-upload-uuid(web-ext 生成的 UUID)改为忽略
2026-10-03 08:37:54 +08:00

116 lines
5.1 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Firefox 扩展:构建 → lint → AMO unlisted 签名 → 发布到数据卷
#
# 为什么需要这个脚本(实测踩坑,2026-10-03):
# 1. 正式版 Firefox 要求扩展经 AMO 签名,未签名一律拒绝并报成「插件损坏」。
# 2. 签名包一旦生成就与内容绑定 —— 改一行代码就必须重新签名,
# 所以「签名」必须跟着「改代码」这一步自动发生,不能靠人记得手动做。
# 3. 签名是 AMO 生成的产物,不该进版本库(签名与源码脱节 + 是二进制),
# 因此落在数据卷里,跨部署存活;nginx 优先供给它(见 nginx.conf)。
#
# 凭据:只从环境变量读,绝不写进本仓库(AGENTS.md §6 脱敏铁律)
# WEB_EXT_API_KEY / WEB_EXT_API_SECRET —— AMO 开发者页面「API 密钥」里的
# JWT issuer:secret。属于程序化签名凭据,与账号密码无关。
# 先在 https://addons.mozilla.org/developers/ → 你的扩展 → 设置 → API 密钥 获取。
#
# 用法:
# WEB_EXT_API_KEY=... WEB_EXT_API_SECRET=... deploy/sign-firefox.sh # 签名并发布
# deploy/sign-firefox.sh --check # 只跑 lint,不签名
set -euo pipefail
SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
EXT_DIR="$SRC/extension/firefox"
WEB_EXT="${WEB_EXT:-npx --yes web-ext@8}"
CHECK_ONLY=0
[ "${1:-}" = "--check" ] && CHECK_ONLY=1
echo "== 1/4 语法与规范检查 =="
node --check "$EXT_DIR/background.js"
node --check "$EXT_DIR/options.js"
node --check "$EXT_DIR/detect.js"
# lint 必须 0 error:AMO 用的是同一个 addons-linter,error 会被直接拒收。
# 注意 notice 不阻塞上传,但要能看见(提示 FUTURE/MV3 之类,不静默吞掉)。
LINT_OUT="$(mktemp)"
trap 'rm -f "$LINT_OUT"' EXIT
(cd "$EXT_DIR/.." && $WEB_EXT lint --source-dir=firefox --output text) >"$LINT_OUT" 2>&1 || {
cat "$LINT_OUT"; echo "!! lint 执行失败" >&2; exit 1; }
grep -E '^(errors|warnings|notices)' "$LINT_OUT" | sed 's/^/ /'
grep -qE '^errors +0' "$LINT_OUT" || { cat "$LINT_OUT"; echo "!! 有 error,AMO 会拒收" >&2; exit 1; }
grep -E '^(NOTICES|WARNINGS):' -A6 "$LINT_OUT" | grep -vE '^--$' | sed 's/^/ /' || true
VER="$(python3 -c "import json;print(json.load(open('$EXT_DIR/manifest.json'))['version'])")"
echo " 版本: $VER"
if [ "$CHECK_ONLY" = "1" ]; then
echo "--check 模式:跳过签名与发布。"
exit 0
fi
echo "== 2/4 AMO 签名(unlisted 自分发)=="
[ -n "${WEB_EXT_API_KEY:-}" ] && [ -n "${WEB_EXT_API_SECRET:-}" ] || {
cat >&2 <<'EOF'
!! 缺少 AMO 凭据。请设置环境变量后重试:
WEB_EXT_API_KEY='user:<id>:<num>' \
WEB_EXT_API_SECRET='<jwt secret>' \
deploy/sign-firefox.sh
凭据在 https://addons.mozilla.org/developers/ → 你的扩展 → 设置 → API 密钥 获取。
不要把凭据写进仓库或任何会被提交的文件(AGENTS.md §6)。
EOF
exit 2; }
ART="$(mktemp -d)"
trap 'rm -rf "$ART" "$LINT_OUT"' EXIT
(cd "$EXT_DIR/.." && $WEB_EXT sign --source-dir=firefox \
--artifacts-dir="$ART" --channel=unlisted --no-input) 2>&1 \
| grep -vE 'DeprecationWarning|trace-deprecation|no version information' | sed 's/^/ /'
XPI="$(ls "$ART"/*.xpi 2>/dev/null | head -1 || true)"
[ -n "$XPI" ] || { echo "!! 未产出签名包" >&2; exit 1; }
echo "== 3/4 校验签名包 =="
# 不能只看「web-ext 说成功」:签名条目缺失的包装上去照样报「插件损坏」。
python3 - "$XPI" <<'PY'
import json, sys, zipfile
z = zipfile.ZipFile(sys.argv[1])
names = z.namelist()
need = ['META-INF/mozilla.rsa', 'META-INF/mozilla.sf', 'META-INF/cose.manifest']
missing = [n for n in need if n not in names]
if missing:
sys.exit(f'!! 签名条目缺失: {missing}')
m = json.loads(z.read('manifest.json'))
g = m['browser_specific_settings']['gecko']
print(f" 签名条目齐备 版本={m['version']} id={g['id']}")
print(f" data_collection={g.get('data_collection_permissions')}")
PY
echo "== 4/4 发布到数据卷 =="
# 没给 NAVI_HOST 就只把包落到本地,供人工上传。
if [ -z "${NAVI_HOST:-}" ]; then
OUT="${1:-$SRC}/navi-firefox-signed.xpi"
cp "$XPI" "$OUT"
echo " 未设 NAVI_HOST,仅本地输出: $OUT"
echo " (线上发布:NAVI_HOST=user@host NAVI_SSH_PASS=... deploy/sign-firefox.sh)"
exit 0
fi
SSH_PASS="${NAVI_SSH_PASS:-}"
if [ -n "$SSH_PASS" ]; then
SSH=(sshpass -p "$SSH_PASS" ssh -o StrictHostKeyChecking=no "$NAVI_HOST")
SCP=(sshpass -p "$SSH_PASS" scp -q -o StrictHostKeyChecking=no)
else
SSH=(ssh -o StrictHostKeyChecking=no "$NAVI_HOST")
SCP=(scp -q -o StrictHostKeyChecking=no)
fi
DATA_DIR="${NAVI_DATA_DIR:-/vol1/docker/navi-data}"
STAMP="$(date +%Y%m%d%H%M%S)"
"${SCP[@]}" "$XPI" "$NAVI_HOST:$DATA_DIR/extension/.navi-firefox.xpi.new"
# 先备份再原子替换:中途失败不会让线上退化成半个文件
"${SSH[@]}" "set -e
cd $DATA_DIR/extension
[ -f navi-firefox.xpi ] && cp -a navi-firefox.xpi navi-firefox.xpi.bak-\$(date +%s)
mv .navi-firefox.xpi.new navi-firefox.xpi
echo \" 已发布: \$(sha256sum navi-firefox.xpi | cut -d' ' -f1)\"" | sed 's/^/ /'
echo "SIGN_OK version=$VER"