惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Attack and Defense Labs
Attack and Defense Labs
V2EX - 技术
V2EX - 技术
C
Cybersecurity and Infrastructure Security Agency CISA
T
Troy Hunt's Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
AI
AI
D
Darknet – Hacking Tools, Hacker News & Cyber Security
L
LINUX DO - 热门话题
W
WeLiveSecurity
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Spread Privacy
Spread Privacy
Simon Willison's Weblog
Simon Willison's Weblog
Security Archives - TechRepublic
Security Archives - TechRepublic
C
Cisco Blogs
S
Security Affairs
V
Vulnerabilities – Threatpost
T
The Exploit Database - CXSecurity.com
P
Privacy & Cybersecurity Law Blog
Security Latest
Security Latest
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Google DeepMind News
Google DeepMind News
博客园_首页
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
T
The Blog of Author Tim Ferriss
Recent Commits to openclaw:main
Recent Commits to openclaw:main
阮一峰的网络日志
阮一峰的网络日志
www.infosecurity-magazine.com
www.infosecurity-magazine.com
T
Threat Research - Cisco Blogs
P
Privacy International News Feed
I
Intezer
The Cloudflare Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
K
Kaspersky official blog
S
Schneier on Security
云风的 BLOG
云风的 BLOG
有赞技术团队
有赞技术团队
爱范儿
爱范儿
博客园 - 叶小钗
博客园 - Franky
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Cloudbric
Cloudbric
V
V2EX
大猫的无限游戏
大猫的无限游戏
Scott Helme
Scott Helme
H
Hacker News: Front Page
SecWiki News
SecWiki News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 【当耐特】

MARKSZのBlog

一次由 pnpm 小版本差异引发的 PicGo 2.5.3 发布事故 极空间虚拟机安装 Ubuntu 24.04 踩坑记录 | MARKSZのBlog 写在 PicGo 即将 8 周年之际 Vite 原理浅析 | MARKSZのBlog Typora 支持 PicGo 来上传图片了 | MARKSZのBlog 用setTimeout和clearTimeout简单实现setInterval与clearInterval | MARKSZのBlog 我的2019春招(暑期实习)记录 | MARKSZのBlog Electron-vue开发实战7——命令行调用与系统级别右键菜单的实现 | MARKSZのBlog Electron-vue开发实战6——开发插件系统之GUI部分 | MARKSZのBlog Electron-vue开发实战5——开发插件系统之CLI部分 | MARKSZのBlog 2018小结 | MARKSZのBlog 图床「神器」PicGo v2.0更新,插件系统终于来了 | MARKSZのBlog 一周一部好电影V【WEEK210 网络迷踪】 | MARKSZのBlog PicGo的star数破1000的心路历程 | MARKSZのBlog 小记VSCode插件amVim的改进以及插件开发 | MARKSZのBlog 基于Koa2开发微信二维码扫码支付相关流程 | MARKSZのBlog 【NOTE】观察者模式VS订阅发布模式 | MARKSZのBlog 【NOTE】进程-线程-协程 关系与区别 | MARKSZのBlog 基于Electron-vue的图床上传工具PicGo v1.5更新说明 | MARKSZのBlog
PicGo 的签名与公证 | MARKSZのBlog
Molunerfinn · 2025-12-25 · via MARKSZのBlog

一直以来,PicGo 并没有做 macOS 的签名和公证,因为一直没注册苹果开发者账号(其实学生时代需要每年出 $99 确实有点贵),所以就会导致用户下载了 PicGo 之后,会遇到这个问题:

App 损坏提示

这个其实也有办法绕过去。不过近几年的 macOS 更新之后,对于应用签名是越来越严格,以前的一行命令还不够,还需要到系统设置里放行比如所有来源的应用之类的。总之门槛越来越高。同时,Homebrew 将在 2026 年 9 月 1 日开始,对于没有通过签名校验的应用,将无法再通过 brew cask 下载安装。趁着这次打算给 PicGo 做点商业化的机会,我也决定注册苹果开发者账号,然后给 PicGo 上签名了。本篇文章就记录一下 Electron 应用在 macOS 上做签名和公证的过程。

1. 获取 Team ID

首先你得注册一个苹果开发者账号,而开发者账号的注册是另外一个话题了(我简单发了篇小红书笔记可以参考),我是用我一直以来的苹果账号注册的,没啥问题,12 月 24 日下午申请注册,24 日晚上就收到通过邮件了。

通过之后,可以在开发者账号页面 找到 Team ID,记录下来,后面有用。

2. 获取证书

我们最终的目标,是导出一个被认证的 p12 文件。

  1. 创建一个 csr 文件
  2. 上传 csr 文件,获得一个 cer 证书
  3. 将证书导入钥匙串,导出 p12 文件。

然后邮件地址我都填的我苹果开发者账号注册的邮箱地址,request 选择存到本地,注意勾上最下面那个指定密钥对!

然后登录 苹果开发者官网 申请证书,我暂时还没打算上架 Mac App Store,先选择 Developer ID Application。

然后导入刚刚的 csr 文件,就能下载这个 cer 证书,证书是有有效期的,意味着到期之后要重新生成。

如果是申请的 Mac Store App 分发的证书,这里将会只有一年的有效期。

然后就可以双击这个文件导入你的证书到 keychain(钥匙链),注意导入到 login(登录) 中。如果发现导入后遇到证书不信任的问题,说明还有一些额外的证书需要先导入。你可以到刚刚在苹果开发者网站申请证书的底部找到这些证书,下载,双击安装到 login 中。


然后把你刚刚那个提示证书不信任的证书,删掉,然后重新导入。重新导入后,你在 Certifacates 或者 My Certificates 里就能看到已经确认的证书信息(注意有个小三角,点开,下面展示是你的私钥,这个很重要,我们需要用它导出 P12 文件)

然后右键证书,导出 P12 文件,这个导出的时候会要求你输入一个密码,这个密码你可以自己定,是用来保护这个 P12 文件的。

导出 P12 文件之后,将其 Base64 字符串导出到剪贴板里,可以复制到某个地方,后文会用到。

1
base64 -i certificate.p12 | pbcopy

3. 创建标识符 && App 专有密码

前往苹果开发者账号页面,创建标识符。

目前来说暂时不用申请什么权限,如果之后需要的话可以再加入就行。输入 Description 和 Bundle ID 即可继续注册。Bundle ID 自己取,独一无二即可,通常的格式页面里也告诉你了。

然后去苹果官方的账号管理页面,申请一个 App Specific Passwords:

申请完成后,需要自己找个地方好好存起来,只会展示一次:

4. 签名和公证

签名和公证在很多时候会被混为一谈,实际上它们是有区别的:

  • 签名 (Code Signing):证明“这是我写的,且没被篡改过”。
  • 公证 (Notarization):证明“苹果查过了,这软件没毒”。

如果没有公证的话,就会遇到经典的 PicGo.app 已损坏 的弹窗。同时,公证的前提是需要有合法的签名。因此注册一个苹果开发者账号,交 $99 年费之后看来是每年必备了。

接下来就是整理和收集上面的各种信息,把它们放到环境变量里,并进行签名和公证了。我自己是在 PicGo 项目的本地创建了一个 .env 文件,内容如下

1
2
3
4
5
6
7
8
9
10

APPLE_TEAM_ID=xxx

APPLE_ID=xxx

APPLE_APP_SPECIFIC_PASSWORD=xxx

CSC_KEY_PASSWORD=xxx

CSC_LINK=xxx

然后因为我用的是 electron-builder,所以只要环境变量里有 CSC_KEY_PASSWORDCSC_LINK 的话,构建的时候就会自动签名。

而公证需要在签名之后,把签名后的 app 文件上传到苹果服务器验证一圈,通过之后你的软件才不会被 gatekeeper 给拦截下来。所以公证我们需要利用 electron-builder config 里的一个 afterSign 的属性,执行一个公证的脚本(利用 electron/notarize 这个包提供的能力),同时根据 electron/notarize 的文档,还需要开启 hardenedRuntime 和一些权限,如下:

1
2
3
4
5
6
7
8
9
10
11
const config = {

afterSign: 'scripts/notarize.js'
mac: {

hardenedRuntime: true,
entitlements: "build/entitlements.mac.plist",
entitlementsInherit: "build/entitlements.mac.plist"
}
}
export default config

然后公证的脚本如下,核心就是调用 @electron/notarize 提供的能力,然后这里需要用到我们刚刚放到 .env 文件里的环境变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

require('dotenv').config()

const { notarize } = require('@electron/notarize')
const { APPLE_ID, APPLE_TEAM_ID, APPLE_APP_SPECIFIC_PASSWORD } = process.env
const APP_BUNDLE_ID = 'com.molunerfinn.picgo'

async function main(context) {
const { electronPlatformName, appOutDir, packager } = context

if (
electronPlatformName !== 'darwin' ||
!APPLE_ID ||
!APPLE_APP_SPECIFIC_PASSWORD ||
!APPLE_TEAM_ID
) {
console.log('Skip notarization.')
return
}

const appName = packager.appInfo.productFilename
const appPath = `${appOutDir}/${appName}.app`

const now = Date.now()

console.log('Starting Apple notarization for', appPath)

await notarize({
appPath,
appBundleId: APP_BUNDLE_ID,
appleId: APPLE_ID,
appleIdPassword: APPLE_APP_SPECIFIC_PASSWORD,
teamId: APPLE_TEAM_ID
})

console.log('Finished Apple notarization for', appPath, `in ${(Date.now() - now) / 1000}s`)
}


module.exports = main

同时还需要准备一个权限文件 entitlements.mac.plist,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>

<key>com.apple.security.cs.allow-jit</key>
<true/>


<key>com.apple.security.cs.disable-library-validation</key>
<true/>


<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
</dict>
</plist>

然后就可以正常构建了,构建完成之后,electron-builder 会自动帮我们进行签名和公证。整个过程大概需要 10 分钟左右,具体时间取决于苹果服务器的响应速度。

最后,本地跑通后,将它们集成到 GitHub Actions 里即可,GitHub Actions 里需要把上面的环境变量都配置好即可。这样做我们就是完成了签名和公证,这样用户从网络上下载 PicGo 就不会再被拦下了:
5359b6e102cc84a6af154e3f320bdcda.png

后续应该会考虑一下如何上架到 Mac App Store,到时候再继续补充吧。

Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.