在 Sandboxed Mac App 中嵌入第三方可执行文件
之前开源了 一个 gitstats 的 GUI 应用 GitStatX,在提交到 GitHub (GitStatX) 之后,又准备提交到 Mac App Store。
在提交到 Mac App Store 之后,出现了一些问题,程序中包含的第三方可执行文件没有签名,导致苹果拒绝了提交的程序包:
App sandbox not enabled – The following executables must include the “com.apple.security.app-sandbox” entitlement with a Boolean value of true in the entitlements property list. Refer to the App Sandbox page for more information on sandboxing your app.
- GitStatX.app/Contents/Resources/git/bin/git
- GitStatX.app/Contents/Resources/gnuplot/gnuplot
但是 GitStatX 所包含的 git 以及 gnuplot,并不是我程序中的代码,也没有 Xcode 工程去使用一个 entitlements 文件来指定它为启用 sandbox 状态。
所幸在网上搜索的时候,找到了可以使用 codesign
工具来进行签名的方法。
检查可执行文件是否启用 sandbox
codesign --display --entitlements - ./commandlinetool
给可执行文件签名并启用 sandbox
先在命令行工具同目录创建一个 entitlements.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
这里设置了 com.apple.security.app-sandbox 为 true 来启用 sandbox。
然后使用 codesign 进行签名:
codesign -s "3rd Party Mac Developer Application: Your Name" --entitlements ./entitlements.plist ./commandlinetool
记得把 “3rd Party Mac Developer Application: Your Name” 替换为实际的证书名称。
问题
在给 gnuplot 签名之后,提交到 Mac App Store,苹果还是会自动验证并发邮件说 gnuplot 没有签名,于是在本地直接导出 GitStatX.app,并检查了一下,发现 gnuplot 的 entitlements 又没有了,但是 git 的 entitlements 还是保留的。在 gnuplot 同目录下,有一个 _CodeSignature 目录,可能是在打包的时候会自动处理。
为了避免这个问题,我就把 gnuplot 也放到了一个 bin 目录下,然后再打包并检查,发现 gnuplot 已经是正确签名并且保留有 entitlements 的了。
当然,GitStatX 最终也正确提交到 Mac App Store,并且程序进入了 Waiting For Review 状态。
参考资料
- Mac OS app, sandbox with command line tool?
- Checking Code Signing and Sandboxing Status in Code
- Entitlement Key Reference
— EOF —
开源 GitStatX:一个 gitstats 的 GUI 应用程序
GitStatX 是一个 gitstatx 的 GUI 应用程序,用于方便在 Mac OS X 中使用 gitstats。
一般情况下,如果要在 Mac OS X 上使用 gitstats,需要自行安装 gnuplot,而这需要使用 macports 或者 homebrew,通常这会比较费时间,并且只能使用命令行来使用 gitstats 生成所对应 git 仓库的报告。
GitStatX 提供了一个 GUI 来使用 gitstats,具备以下功能:
- 同时管理多个项目
- 使用分组来归类各个项目
- 标识项目类型
- 自动生成报告
- 导出仓库的活动报告
截图
项目主页
tickplant.com/gitstatx/
仓库地址
https://github.com/ohdarling/GitStatX
下载
查看所有下载
授权
本软件及代码以 GPLv3 授权发行。
相关代码
- 使用 bootstrap 样式的 gitstats: https://github.com/ohdarling/gitstats
- 修正可执行文件依赖库的脚本: https://gist.github.com/4225568
联系我
- Twitter: @ohdarling88
- Email: ohdarling88 at gmail
— EOF —
使用 ukraine 建设 node.js 私有云
源由
node.js 越来越流行,托管 node.js 应用的云服务也越来越多,例如 nodejitsu、heroku 等。
但是这些云服务通常有这样那样的限制,又或者是要收费的。而有些时候我通常不需要跑很大的应用,或者是很稳定的应用,只是为了跑一些小的,或者是学习用的 node.js 应用,并且我也有自己的 VPS,想把这些应用托管在自己的服务器上。
于是我需要去找一个可以在自己的 VPS 上建设一个 node.js 私有云的软件。
比较
在看了 https://github.com/joyent/node/wiki/Node-Hosting 中的 DIY Platforms 后,尝试了一下其中介绍的平台:
- nodester: 安装比较麻烦,不支持新版本的 nodejs,安装说明还是针对 node 0.4.11 的
- CloudFoundry: 比较庞大,而且是以 vm 方式安装,不适合 VPS
- OpenShift: 同 CloudFoundry,不只支持 node.js,安装复杂,不适合 VPS
- Nodejitsu: Nodejitsu 开源了他们所用的 node.js 应用管理项目 haibu,haibu 安装比较简单,而且支持最新的 nodejs 0.8.16,不过 Nodejitsu 同样开源的命令行客户端 jitsu 并不支持 haibu
- Stagecoach: 文档不够清晰,看了很久也没明白它的架构和怎么部署⋯⋯
这样看来似乎没有一个可以满足我的需要,不过 GitHub 是强大的,通过搜索找到了 ukraine 这个项目:
ukraine glues haibu and node-http-proxy adding a little helper, chernobyl, that deploys into this cloud. It is probably as stable as you think it is.
这就是我想要的。
修改
原始的 ukraine 虽然已经基本满足了我的需要,但是还有一些小的功能需要增加:
- 使用 nginx 作为前端,这样 node.js 应用可以部署在 nginx 后面,与 PHP 等项目并存
- 使用 SSL 保护 haibu 的服务端,防止 auth_token 因为不加密的 HTTP 通信而泄漏
- 因为使用 nginx 作为前端,所以 haibu 服务端和 node-http-proxy 都不需要监听 0.0.0.0,而只需要监听 127.0.0.1
- 防止 node.js 应用监听了常用端口而导致其他应用启动失败,因为使用了 nginx 作为前端,node.js 应用本身监听了什么端口就不重要了
- 防止 node.js 应用直接对外提供服务,同样因为已经有 nginx,node.js 应用只需要监听 127.0.0.1 就行了
- chernobyl 不支持配置每个不同的 ukraine 监听在哪个端口,以及有没有配置 SSL
- 我想 ukraine 作为一个服务存在,这样在 VPS 启动时可以自动启动
- node.js 应用需要支持绑定自定义域名,而不是只能绑定子域名
所以我 fork 了 radekstepan 的 ukraine 到 https://github.com/ohdarling/ukraine,并做了一些自己需要的修改。
安装修改后的 ukraine
如果你和我一样,也需要一个这样简单的 node.js 私云,那么以下的内容可以帮助里部署 ukraine 到自己的 VPS 上。
注意:安装教程以在 Ubuntu/Debian 上为例,并且所有命令是以 root 用户执行。
1. 安装 node.js
haibu 需要 node.js 的版本大于 0.8,所以需要安装最新的 node.js 包,或者自行编译安装。
参考这篇文章:Installing Node.js via package manager
2. 安装 forever
forever 是用来维持 ukraine 一直在启动状态
npm install forever -g
3. 配置 nodejs 用户
为了使所有 node.js 应用不使用 root 权限运行,防止出现权限方便的风险,需要添加一个用户 nodejs
来运行 node.js 应用。
groupadd nodejs
useradd -g nodejs -m -s /bin/bash nodejs
4. 获取并安装 ukraine
为了管理方便,这里安装 ukraine 到 /srv/ukraine 中,如果你不安装在这个位置,那么相关的脚本和配置文件都需要修改。
cd /srv
git clone https://github.com/ohdarling/ukraine
cd ukraine
git checkout private-cloud
npm install
chown -R nodejs.nodejs /srv/ukraine
5. 配置 ukraine
cd /srv/ukraine
cp config.example.json config.json
vim config.json
为了安全起见,建议 auth_token 不要留空。
example.com
需要替换为你自己的域名,这样以后部署了 node.js 应用时,会自动分配一个 package-name.example.com 的子域名。
6. 安装服务脚本
注意:这个脚本只适用于 Ubuntu/Debian。
cd /srv/ukraine
cp server/init-script/ukraine /etc/init.d/
chmod +x /etc/init.d/ukraine
7. 使用 nginx 作为前端服务
为了使 node.js 应用与原有的 PHP 共存,使用 nginx 作为 ukraine 的前端服务。
注意:部署 node.js 应用到 ukraine 需要 nginx 启用 chunkin 模块,默认情况下 nginx 并没有安装此模块,可以自行编译安装(参考 wiki.nginx.org/NginxHttpChunkinModule),或者直接使用包管理器安装 nginx-extras
,这个包中包含的 nginx 已经编译了 chunkin 模块。
添加以下配置文件内容到 /etc/nginx/sites-available/ukraine
,并且在 /etc/nginx/sites-enabled/
中添加一个到配置文件的符号链接。注意,需要替换配置文件内容中的 haibu.example.com
和 *.example.com
为你自己的域名。
server {
listen 80;
server_name haibu.example.com;
access_log /var/log/nginx/localhost.access.log;
chunkin on;
error_page 411 = @my_411_error;
location @my_411_error {
chunkin_resume;
}
location / {
proxy_pass localhost:9002;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 80;
server_name *.example.com;
access_log /var/log/nginx/localhost.access.log;
location / {
proxy_pass localhost:8000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
}
}
建议在 haibu.example.com 这个站点上启动 SSL 来保护 auth_token。
添加完配置文件后,使用以下命令让 nginx 重新载入配置:
nginx -s reload
8. 启动 ukraine
service ukraine start
9. 检查 ukraine 是否正常运行
打开浏览器,访问 haibu.example.com/version
,将会看到以下内容:
{"version":"haibu 0.9.7"}
注意,如果在之前已经配置了 auth_token,将会看到:
{"message":"Wrong auth token"}
这说明 ukraine 已经正常启动。
部署自己的 node.js 应用
首先需要在本地安装 ukraine:
npm install -g git://github.com/ohdarling/ukraine\#private-cloud
如果之前配置了 auth_token:
chernobyl config haibu.example.com auth_token=xxxx
如果之前配置了 SSL:
chernobyl config haibu.example.com https=true
chernobyl config haibu.example.com haibu_port=443
现在可以部署 node.js 应用了,进入到 node.js 应用的根目录,运行以下命令:
chernobyl deploy haibu.example.com .
这就会部署这个 node.js 应用到 haibu.example.com 了。
给 node.js 应用绑定自定义域名
在给 node.js 绑定自定义域名,只需要在 package.json
中添加 domains
属性即可:
{
"name": "example-app",
"version": "0.0.2",
"domains": [
"custom-example.com"
]
"dependencies": {
"express": "2.5.x"
},
"scripts": {
"start": "server.js"
}
}
同样需要修改 nginx 的配置文件,把自定义域名加到 server_name 中:
server {
listen 80;
server_name *.example.com, custom-example.com;
access_log /var/log/nginx/localhost.access.log;
location / {
proxy_pass localhost:8000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
}
}
注意事项
- 所有 node.js 应用会监听在一个随机端口,并且会监听在 127.0.0.1,也就意味着在外部没有办法直接访问这个应用
package.json 中 scripts.start 属性,不需要带 node,只需要指定以哪个脚本启动即可,例如以下是错误的:
{ “name” : “example-app”, “scripts” : { “start” : “node server.js” } }
如果需要 node.js 鉴定特定的端口,并能直接对外服务,可以在 package.json 的 env 属性中添加 “HAIBU_INDEPENDENT_SERVICE”: “true”,例如:
{ “name” : “somesocks”, “scripts” : { “start” : “server.js” }, “env” : { “HAIBU_INDEPENDENT_SERVICE” : “true” } }
问题及反馈
你