Skip to content

Instantly share code, notes, and snippets.

@shellexy
Created April 18, 2012 13:55
Show Gist options
  • Save shellexy/2413736 to your computer and use it in GitHub Desktop.
Save shellexy/2413736 to your computer and use it in GitHub Desktop.
生成网页版 hotot
#!/bin/bash -x
SRC=$PWD/data/
DEST=$PWD/web.hotot.org/
echo "\033[1;31;40m[i]Sync ...\033[0m"
# ignore .*.swp, .hgignore, etc
rsync -av --exclude '.*.*' --exclude '*.coffee' --exclude 'test*' $SRC $DEST
# replace conf.vars.platform, key and secret
echo "\033[1;31;40m[i] Replace platform, key and secret ...\033[0m"
sed -i "s/'platform': '\w*'/'platform': 'Web'/g" ${DEST}js/conf.js
sed -i "s/'consumer_key': '\w*'/'consumer_key': '604L17uwIwWsT1TIyjBTQA'/g" ${DEST}js/conf.js
sed -i "s/'consumer_secret': '\w*'/'consumer_secret': 'eB7cjPzO9QGZi50jpdrlIPtpPvlKkdt18uahit5oYE'/g" ${DEST}js/conf.js
echo "\033[1;31;40m[i] Done!\033[0m"
## ###########################
cat >> ${DEST}js/hotot.js <<OOO
if (conf.vars.platform === 'Web') {
var URL = document.URL.replace(/\/[^\/]+$/, '/');
window.XMLHttpRequest.prototype.open_ = window.XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
url = url.replace('https://', '/');
url = url.replace('http://', '/');
return this.open_(method, url, async, user, password);
}
ui.PinDlg.set_auth_url_ = ui.PinDlg.set_auth_url;
ui.PinDlg.set_auth_url = function(url){
return ui.PinDlg.set_auth_url_(url.replace('https://api.twitter.com/', URL + 'itap/'));
}
}
OOO
## html5 cache
(
cd ${DEST:-.}
echo -e 'CACHE MANIFEST\n' > cache.manifest
echo -e 'NETWORK:\n*\n' >> cache.manifest
echo 'CACHE:' >> cache.manifest
find . -type f | grep -Ev '^\./itap|\.gz$|cache\.manifest|cache\.html|index\.html' | sed 's/^\.\///; s/ /%20/g' >> cache.manifest
echo "# `date -R`" >> cache.manifest
sed -i 's/<html.*>/<html lang="en" manifest="cache.manifest">/' index.html
mv index.html hotot.html
echo '<html><head><meta http-equiv="no-cache" /><title>Hotot</title></head><frameset><frame src="hotot.html"></frameset></html>' > index.html
)
sed -i "s/'use_alt_reply': \w*/'use_alt_reply': true/g" ${DEST}js/conf.js
convert -quality 30 ${DEST}/image/welcome_bg.jpg ${DEST}/image/welcome_bg.jpg
which yui-compressor && find "$DEST" -name '*.css' -exec yui-compressor -o "{}" "{}" \;
which uglifyjs && find "$DEST" -name '*.js' -exec uglifyjs --overwrite "{}" \;
@beersun
Copy link

beersun commented Apr 20, 2012

我这边apache的 所以还得写.htaccess啊。。。

白熊大大那么厉害一定能写好的

醒醒 鶸渣渣一只好吧

@elvisw
Copy link

elvisw commented Apr 20, 2012

23333……其实咱也不会写……不过大家都用apache啊

@shellexy
Copy link
Author

暂时改用框架来强制不缓存首页

@lainMeow
Copy link

(来试试 comment 能不能张贴长篇大论)

雪梨老师前天布置的作业,于是算是交作业(草稿)

主要步骤大致整理如下:

第一部分 准备工作
  源码获取以及雪梨写的脚本中用到了这些工具:

git
hg (mercurial)
wget
convert (ImageMagick)
yui-compressor
uglifyjs

  鉴于通常咱们的VPS都是以最精简状态安装操作系统的(从留言的评论看,甚至可能连wget命令都没有),因此我们需要将上述工具预先准备好(其中css/js压缩器yui-compressor和uglifyjs为可选)。
  我的VPS操作系统是CentOS,可以通过yum自动完成安装,命令如下:

  yum install git hg wget ImageMagick

  使用其他操作系统的请酌情办理 =w= (谁来补充一下w

  剩下的yui-compressor和uglifyjs,用于压缩js和css代码。这两个不是必需品。可选安装。
  在debian/ubuntu 里可以直接 apt 安装:

sudo apt-get install yui-compressor node-uglify

  如果是CentOS,则略麻烦一些(没有找到包含它们的yum源),需要手动安装。
  不过反正是可选步骤,不装也可以。
  其中,安装yui-compressor的主要步骤是:


wget http://yui.zenfs.com/releases/yuicompressor/yuicompressor-2.4.7.zip
unzip yuicompressor-2.4.7.zip
mkdir -p /usr/local/yuicompressor/
cp yuicompressor-2.4.7/build/yuicompressor-2.4.7.jar /usr/local/yuicompressor/yuicompressor-2.4.7.jar

cat >> /usr/bin/yui-compressor << EOF

!/bin/sh

YUI_JAR=/usr/local/yuicompressor/yuicompressor-2.4.7.jar
java -jar $YUI_JAR $1 "$2" "$3"
EOF

chmod a+rx /usr/bin/yui-compressor


  (要正常使用yui-compressor,请确保系统中已安装好Java运行时环境)

  yuicompressor通常情况下是以

  java -jar /path/yuicompressor-x.y.z.jar [options] [input file]

  的形式调用的;但是观测到雪梨的脚本中似乎是直接以yui-compressor这个命令的形式调用的,不知道是怎么实现的呢?
  (于是我把它写成了 /usr/bin/yui-compressor 这个脚本;不过感觉这个方法还不够漂亮不够优美哈...于是求好方法)
  
  

  安装uglifyjs的主要步骤是:

  首先需要下载源码并编译安装node.js

  wget http://nodejs.org/dist/v0.6.15/node-v0.6.15.tar.gz
  tar xzvf node-v0.6.15.tar.gz
  cd node-v0.6.15
  ./configure
  make
  sudo make install

  然后

mkdir -p /放置路径
cd /放置路径
git clone git://github.com/mishoo/UglifyJS.git

mkdir -p ~/.node_libraries/
cd ~/.node_libraries/
ln -s /放置路径/UglifyJS/uglify-js.js

cd /usr/local/bin
ln -s /放置路径/UglifyJS/bin/uglifyjs

  即可。
  以上,工具的准备工作告一段落。
  
  

第二部分 生成网页版Hotot发布目录内容

  雪梨写了部署脚本,因此可以很方便地实现,命令步骤如下:

## 抓回 hotot
git clone --depth 0 git://github.com/shellex/Hotot.git
cd Hotot
## 生成 web.hotot.org 目录
wget https://raw.github.com/gist/2413736/mk-hotot-web.sh
bash -x mk-hotot-web.sh
cd web.hotot.org
## 抓回 itap
hg clone https://bitbucket.org/aveline/itap

  上述执行完毕后应该出现一个web.hotot.org目录;在web.hotot.org目录下有一个itap目录。
  编辑itap目录下的handler.php =文件。找到其中的 auth_post() 函数;在函数的 echo $response; 那一行下方添加以下内容:

echo '<script>code = document.querySelector("code").innerText; opener.$("#tbox_oauth_pin").val(code); opener.$("#btn_oauth_pin_ok").click(); setTimeout(window.close, 1000);</script>';

  保存退出。此时网页版的发布内容已基本准备妥了。

  
  

第三部分 Nginx配置
  
  

  1. 申请SSL证书
      由于大家都知道的原因,网页版Hotot是在互联网上公开地放置Play,如果数据明文传输的话,对于我们的宝贵域名、宝贵VPS、宝贵IP都不是很安全……万一被墙嗅出来然后炮灰掉,那可真的很糟糕……何况大墙最近技艺似乎确实日渐精进,非加密连接的 tw*p 们已经纷纷被ban,速度很快效率很高。因此除非手持炮灰米+炮灰主机,否则还是强烈建议去弄个证书,使用HTTPS加密连接。

  申请免费SSL证书的流程可参考:
  http://www.deepvps.com/apply-startssl-ssl-certificate.html
  这里不再赘述。

  验证域名所有者时需要使用whois记录中的管理猿邮箱,请保证whois记录真实准确(至少临时真实个几天吧w);或者使用 webmast@yourdomain.com 这样的域名邮箱也行,可以去借助Google提供的免费企业应用服务实现。

  证书弄回来之后,还是需要小加工一下的。我们需要把 StartSSL 的根证书和sub class1的证书附上,因为是它把证书颁发给我们,浏览器需要这张证书才认识我们的证书。
  如果不进行该操作,部分浏览器会报告证书不可信(据说=w=),同时一段时间后也会收到StartSSL网站类似的邮件提醒。

  假设保存的私钥文件名为 ssl.key ;证书文件名为 ssl.crt ,上传到VPS的某个目录保存,然后在VPS上执行命令如下:

  wget http://cert.startssl.com/certs/ca.pem
  wget http://cert.startssl.com/certs/sub.class1.server.ca.pem
  echo >> ssl.crt
  cat ca.pem sub.class1.server.ca.pem >> ca-certs.crt
  cat ca-certs.crt >> ssl.crt
  openssl rsa -in ssl.key -out ssl.key.decrypted

  
  注意步骤中 echo >> ssl.crt ,其作用是在 ssl.crt 后插入回车换行,再拼接CA证书。
  度娘搜出来排在头上的几篇文,都遗漏了插入换行这一步,因此拼接出的证书格式变成了有误的,Nginx启动时会报错无法启动。

  此外,如果直接使用加密的私钥文件ssl.key,启动Nginx时候会要求输入密码,这样Nginx就不能开机自动启动了,很不方便。在此我们将其解密导出为PEM文档,Nginx启动时就无需输入密码了。当然这么做的话,该文件务必要保管好,切不可外流。

  搞定证书之后就可进行Nginx子站的配置。请将第二部分中准备好的 web.hotot.org 文件夹作为子域名根目录发布出去。下面是我的配置文件,供参考。

  本例中假定的环境情况罗列如下,实际应用时请酌情修改:
  IPv4地址:         123.123.123.123
  IPv6地址:         AAAA:AAAA:AAAA:AAAA::AAAA
  绑定的域名:        Meow.Meow
  发布文件夹保存路径:    /home/web.hotot.org
  证书文件地址:       /etc/nginx/certs/Meow.Meow/ssl.crt;
  私钥地址(使用解密的):  /etc/nginx/certs/Meow.Meow/ssl.key.decrypted;

#非加密连接相关配置部分
server
        {
                #无IPv6地址时,IPv6那一行可直接删除;
                #若要支持IPv6,则所有Server的v4和v6地址必须同时全部写明,不能只写80
                listen   123.123.123.123:80;
                listen   [AAAA:AAAA:AAAA:AAAA::AAAA]:80;

                #DNS服务器8.8.8.8,作正向代理时必须设置
                resolver 8.8.8.8;
                server_name Meow.Meow;
                index index.html index.htm index.php default.html default.htm default.php;
                root  /home/web.hotot.org;
                
                #若想配置为HTTP/HTTPS兼用(可选加密),则注释掉下面这行即可
                #默认强制跳转至加密方式入口,永远不使用非加密连接
                rewrite ^(.*) https://$server_name$1 permanent;

                #仅支持基于WebKit引擎的浏览器(Safari/Chrome,经测试Maxthon也可用)
                if ($http_user_agent !~ "Chrome|Safari") { return 404; }

                location ~ .*\.(php|php5)?$
                {
                        fastcgi_pass  unix:/tmp/php-cgi.sock;
                        fastcgi_index index.php;
                        fastcgi_param  HTTPS on;
                        include fcgi.conf;
                }

                location ~ (twitter\.com) {
                  if ( $request_uri = "/" ) {
                    return 404;
                  }
                  access_log  off;
                  proxy_buffering off;
                  proxy_set_header Referer $scheme:/$request_uri;
                  proxy_pass "https:/$request_uri";
                }
                location ~ (img\.ly|plixi\.com|google\.com) {
                  if ( $request_uri = "/" ) {
                    return 404;
                  }
                  access_log  off;
                  proxy_buffering off;
                  proxy_set_header Referer $scheme:/$request_uri;
                  proxy_pass "http:/$request_uri";
                }
              
                location ~ (hotot\.in\/) {
                  if ( $request_uri = "/" ) {
                    return 404;
                  }
                  access_log  off;
                  proxy_buffering off;
                  proxy_set_header Referer $scheme:/$request_uri;
                  proxy_pass "http:/$request_uri";
                }

                location /itap/ {
                  access_log off;
                  if (!-e $request_filename) {
                    rewrite ^(.*) /itap/index.php last;
                  }
                }
                location / {
                  access_log off;
                  gzip_static on;
                  gzip  on;
                  gzip_min_length  1000;
                  gzip_types  text/plain application/x-javascript text/css;
                  expires 2d;
                  add_header Cache-Control public;
                }
                access_log off;
        }

#加密连接相关配置部分
server
        {
                #无IPv6地址时,IPv6那一行可直接删除;
                #需要启用IPv6时,则所有Server的v4和v6地址必须同时全部写明不能只写80
                listen   123.123.123.123:80;
                listen   [AAAA:AAAA:AAAA:AAAA::AAAA]:80;

                #DNS服务器8.8.8.8,作正向代理时必须设置
                resolver 8.8.8.8;
                server_name Meow.Meow;
                index index.html index.htm index.php default.html default.htm default.php;
                root  /home/web.hotot.org;

                #使用解密后的私钥文件,启动Ngnix时不输入密码
                ssl on;
                ssl_certificate /etc/nginx/certs/Meow.Meow/ssl.crt;
                ssl_certificate_key /etc/nginx/certs/Meow.Meow/ssl.key.decrypted;

                #仅支持基于WebKit引擎的浏览器(Safari/Chrome,经测试Maxthon也可用)
                #由于主机中还托放有API代理供Android手机使用,酌情添加了相应客户端
                if ($http_user_agent !~ "Chrome|Safari|Dalvik|Seesmic") { return 404; }
              
                location ~ .*\.(php|php5)?$
                 {
                         fastcgi_pass  unix:/tmp/php-cgi.sock;
                         fastcgi_index index.php;
                         fastcgi_param  HTTPS on;
                         include fcgi.conf;
                 }

                location ~ (twitter\.com) {
                  if ( $request_uri = "/" ) {
                    return 404;
                  }
                  access_log  off;
                  proxy_buffering off;
                  proxy_set_header Referer $scheme:/$request_uri;
                  proxy_pass "https:/$request_uri";
                }

                location ~ (img\.ly|plixi\.com|google\.com) {
                  if ( $request_uri = "/" ) {
                    return 404;
                  }
                  access_log  off;
                  proxy_buffering off;
                  proxy_set_header Referer $scheme:/$request_uri;
                  proxy_pass "http:/$request_uri";
                }
              
                location ~ (hotot\.in\/) {
                  if ( $request_uri = "/" ) {
                    return 404;
                  }
                  access_log  off;
                  proxy_buffering off;
                  proxy_set_header Referer $scheme:/$request_uri;
                  proxy_pass "http:/$request_uri";
                }

                location /itap/ {
                  access_log off;
                  if (!-e $request_filename) {
                    rewrite ^(.*) /itap/index.php last;
                  }
                }
                location / {
                  access_log off;
                  gzip_static on;
                  gzip  on;
                  gzip_min_length  1000;
                  gzip_types  text/plain application/x-javascript text/css;
                  expires 2d;
                  add_header Cache-Control public;
                }
                access_log off;
        }

  由于目前只有基于WebKit的浏览器能良好支持,所以加入了if ($http_user_agent !~ "Chrome|Safari") { return 404; } 这么一行,用于限制浏览器种类;不能支持的IE/FF访问时,只能看到404提示。Safari和Chrome肯定是能用的,抓来个Maxthon 3.0试试也行,还有哪些呢…不知道其他数不清的天朝产的“双核”奇葩们会是啥子模样……不过没兴趣安装折腾它们了。

  因为发布目录下还寄放有API代理(给Android手机用的),因此可以酌情再添加上相应的客户端标识(Dalvik | Seesmic 等),不然API就用不起来了。

  Nginx的配置中,resolver 8.8.8.8这一行挺关键的。Nginx 作为“普通青年”(基本用途)是作为Web服务器/反向代理服务器;但是在我们部署网页版Hotot用于访问Twitter的时候,作为“文艺青年”的Nginx其实是发挥了它的正向代理功能。因为Nginx不会自动读取系统的DNS去解析域名,这就需要我们定义一个resolver指定DNS服务器地址。
  之前忘了加上这句resolver,于是从获取token那一步开始起就死住了。
  顺便说示一个小技巧,如果你部署的Hotot时遇到各种问题玩不转,Chrome F12的开发者工具会是很不错的debug手段哦,如图所示。http://twitpic.com/9fcht3/full 可以发现问题是连不上api.twitter.com,于是顺藤摸瓜之,发现原因所在。(爬墙呢喵……爬墙呢喵……啊呜从墙上摔下来了喵…痛痛痛……啊呜啊呜终于验证通过了喵)
  
  

第四部分 一点障眼法

  说起来,傲兔兔什么的最好用了……但是对于哔哔哔来说,这货的存在最讨厌了……域名私藏好,低调地用吧。

  鉴于大墙已经开始无差别撒大网封禁架设无加密TW_P服务的域名了(而不像以前只抓大户),使用加密连接应该是一个靠谱的保证;此外,是不是还需要设置一些障眼法什么的呢?
  
  一方面,肯定是要用私藏的二级域名,最好是炮灰域名;避免用顶级域名或者www._;

  此外咱们也可以让Nginx绑定一个根本不存在的域名嘛……然后本机写hosts文件,直接指向这个捏造的域名(咳咳…我什么都没说……遁)

  譬如使用华丽丽的Hotot.Meow(喂等一等…Hotot是兔子亚,为什么喵叫…) http://twitpic.com/9fciqw/full 这样就算通过抓包的方式被发现了,也ban不掉什么真金白银买来的宝贝域名撒……哦对了还可以直接ban主机的IP(跪

  
  
  
以下这段是过去时的讨论了……因为已经想通了,不会有安全隐患的说w
但是封禁直接以IP地址访问的方法,有时候还是用得着的,所以暂保留:


  最后,我在担心考虑的是,虽然地址自己不会泄露出去,但是爬虫是个很讨厌的家伙……如果遭遇爬虫直接根据IP前来访问,怎么办呢?
  考虑到虽然Ngnix里面绑定了域名,但是如果没有停放其他使用443端口的加密连接站点(毕竟一般服务器上都只配置了非加密的默认站点吧),用IP直接访问的时候,一旦手动发起443端口的HTTPS连接(爬虫会这样做么?)还是会直达我们的的首页。因为这是这台服务器上是唯一的加密站点,所以Ngnix把它作为了默认的(虽然会警告证书不匹配)提供给爬虫。
  
  (于是到底会不会被爬虫抓呢?直接扫IP然后摸进来什么的?)

  总之觉得这样还是不好、不安全不放心……(也许是我迫害妄想症……)所以打算要禁用IP直接访问、以及未经绑定的域名的访问。

  普通青年的方法很简单,在真·站点之前绑个空的dummy站就行了,取代真·站点成为默认站点。还可外加跳转。(以下配置文字一定要写在真·站点的server段之前,才能有效哦)

#如果80端口已有默认站点的话,第一个server段可以不要

server
        {
                listen   123.123.123.123:80;
                listen   [AAAA:AAAA:AAAA:AAAA::AAAA]:80;
                server_name Meow.Meow;
                index index.html index.htm;
                root  /dev/null;                
                return 404;
                access_log off;
        }

server
        {
                listen   123.123.123.123:443;
                listen   [AAAA:AAAA:AAAA:AAAA::AAAA]:443;
                server_name Meow.Meow;
                index index.html index.htm;
                root  /dev/null;
                
                ssl on;
                ssl_certificate /etc/nginx/certs/Meow.Meow/ssl.crt;
                ssl_certificate_key /etc/nginx/certs/Meow.Meow/ssl.key.decrypted;

                rewrite ^(.*) http://$host$1 permanent;
                access_log off;
        }

说到拿 HTTP 返回值做障眼法,错误返回值其实可以随便写?只要是RFC协议里面定义的就行。比如:
普通青年用 return 404 Not found ;
文艺青年用 return 415 Unsupported media type ;
二逼青年用 return 402 Payment Required ;
(你够了……

如果是213青年,大概有更213的做法,类似于可以这样:

server
        {
                listen   123.123.123.123:443;
                listen   [AAAA:AAAA:AAAA:AAAA::AAAA]:443;
                server_name Meow.Meow;
                if ($host !~ "Meow.Meow") { rewrite ^(.*) http://Nyaa.Nyaa permanent; }

                index index.html index.htm;
                root  /dev/null;
                
                ssl on;
                ssl_certificate /etc/nginx/certs/Meow.Meow/ssl.crt;
                ssl_certificate_key /etc/nginx/certs/Meow.Meow/ssl.key.decrypted;
                access_log off;
                …………
                …………
                …………
                …………
                下略
}

  如果来访所使用的主机名并非绑定的域名,则直接跳转到一个根本不存在的站点……(两种方法哪种更优雅一些呢……?

  最后再配合robots.txt,再把index.html改掉,这样感觉应该差不多了吧……

  //补:呃,折腾那么多……刚刚才忽然想起来,爬虫bot提交的客户端肯定不会是Chrome| Safari……
  Google是 Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
  Baidus是 "Baiduspider+(+http://www.baidu.com/search/spider.htm)"
  所以按照之前写的Ngnix规则只能抓到HTTP错误信息……
  因此是我多虑了吧……
  不过写都写了那么多了那还是留着吧(跪 ……好吧,不防bot防防活人也好
wwww


@shellexy
Copy link
Author

赞下阿喵

噢,是酱紫的,debian/ubuntu 里可以直接 apt 安装 yui-compressor 和 uglifyjs

sudo apt-get install yui-compressor node-uglify

或许需要再强调下这俩是可选的?尤其是 java 程序实在有些那啥,
不过如果装过 nodejs 的话,可以选择用无需 java 的 uglifycss 来压缩 css

@shellexy
Copy link
Author

跑题下,错误代码大概还是用 404 比较好些,已经删除?

402 的话有这个是用来牟利的嫌疑?

虽然我自己是用的 401

@lainMeow
Copy link

啊呜…402是我昨天耍宝耍213,自己弄着玩儿的……
配置文件直接粘贴过来了……没想到居然还遗漏了一处402没改回去
已经改了w

另外yui-compressor 和 uglifyjs的相关也做了更新。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment