在 Sandboxed Mac App 中嵌入第三方可执行文件

Posted by Xu Jiwei on February 5, 2013 No comments

之前开源了 一个 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 状态。

参考资料

  1. Mac OS app, sandbox with command line tool?
  2. Checking Code Signing and Sandboxing Status in Code
  3. Entitlement Key Reference

— EOF —

开源 GitStatX:一个 gitstats 的 GUI 应用程序

Posted by Xu Jiwei on January 10, 2013 2 comments

GitStatX 是一个 gitstatx 的 GUI 应用程序,用于方便在 Mac OS X 中使用 gitstats。

一般情况下,如果要在 Mac OS X 上使用 gitstats,需要自行安装 gnuplot,而这需要使用 macports 或者 homebrew,通常这会比较费时间,并且只能使用命令行来使用 gitstats 生成所对应 git 仓库的报告。

GitStatX 提供了一个 GUI 来使用 gitstats,具备以下功能:

  • 同时管理多个项目
  • 使用分组来归类各个项目
  • 标识项目类型
  • 自动生成报告
  • 导出仓库的活动报告

截图

spacer

项目主页

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 私有云

Posted by Xu Jiwei on January 9, 2013 No comments

源由

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 虽然已经基本满足了我的需要,但是还有一些小的功能需要增加:

  1. 使用 nginx 作为前端,这样 node.js 应用可以部署在 nginx 后面,与 PHP 等项目并存
  2. 使用 SSL 保护 haibu 的服务端,防止 auth_token 因为不加密的 HTTP 通信而泄漏
  3. 因为使用 nginx 作为前端,所以 haibu 服务端和 node-http-proxy 都不需要监听 0.0.0.0,而只需要监听 127.0.0.1
  4. 防止 node.js 应用监听了常用端口而导致其他应用启动失败,因为使用了 nginx 作为前端,node.js 应用本身监听了什么端口就不重要了
  5. 防止 node.js 应用直接对外提供服务,同样因为已经有 nginx,node.js 应用只需要监听 127.0.0.1 就行了
  6. chernobyl 不支持配置每个不同的 ukraine 监听在哪个端口,以及有没有配置 SSL
  7. 我想 ukraine 作为一个服务存在,这样在 VPS 启动时可以自动启动
  8. 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;
    }
}

注意事项

  1. 所有 node.js 应用会监听在一个随机端口,并且会监听在 127.0.0.1,也就意味着在外部没有办法直接访问这个应用
  2. package.json 中 scripts.start 属性,不需要带 node,只需要指定以哪个脚本启动即可,例如以下是错误的:

    { “name” : “example-app”, “scripts” : { “start” : “node server.js” } }

  3. 如果需要 node.js 鉴定特定的端口,并能直接对外服务,可以在 package.json 的 env 属性中添加 “HAIBU_INDEPENDENT_SERVICE”: “true”,例如:

    { “name” : “somesocks”, “scripts” : { “start” : “server.js” }, “env” : { “HAIBU_INDEPENDENT_SERVICE” : “true” } }

问题及反馈

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.