2013年4月23日 星期二

Upload File

上傳一直是寫Web程式的開發人員不可或缺的一個口袋工具
Node.js針對上傳部分,比較普遍的是使用ExpressJS的上傳設定
而原生的http模組,也一樣可以做到上傳...
下面是網路上找到的兩筆不同上傳的範例:

2013年4月2日 星期二

NodeJS ssh sign and verify : ssh-signer


Ssh-signer(GitHub: https://github.com/peihsinsu/ssh-signer),開發的目的是希望提供一個使用crypto與http-signature的簽章與驗證工具...讓client端與server端可以直接安裝一個套件就可以做到簽章跟認證的動作...

安裝

npm install ssh-signer

使用

準備...載入相關modules並且準備opt參數(選用,不一定要放,沒放會使用預設 alg=RSA-SHA256, hash=base64)
var signer = require('ssh-signer')
  , fs = require('fs');

var opt = {
  alg:'RSA-SHA256',
  hash:'base64'
}
SSH key簽章 (opt選用)
//sign a key from public key path
var a = signer.signPrivateKey( 'Test123', '/root/.ssh/id_rsa', opt);

//sign a key from public key string
var privKeyStr = fs.readFileSync('/root/.ssh/id_rsa', 'UTF-8');
var a = signer.signPrivateKeyStr( 'Test123', privKeyStr, opt);
驗證 (opt選用)
//verify a key from public key path
var b = signer.verify(a, 'Test123', '/root/.ssh/id_rsa.pub', opt);

//verify a key from public key string
var pubKeyStr = fs.readFileSync('/root/.ssh/id_rsa.pub', 'UTF-8');
var b = signer.verifyStr(a, 'Test123', pubKeyStr, opt );
console.log('Verify result ==> ' + b); //will show true or false

SSH key sign & verify...

繼Node.js收錄crypto之後,還沒有機會實作相關功能
透過SSH key來做client與server間的認證會是各不錯的sample...

下面展示將ssh key的privare key跟public key做sign與verify的流程
屆時將private key放在client端,public key可以load在server端(目前MiCloud上管理ssh key的方式)
中間透過時間字串做key的hash減少傳輸中間key背破解的風險...

//STEP1: 載入crypto, http-signature兩各主要使用模組
var crypto=require("crypto");
var sys=require("sys");
var fs=require("fs");
var hs = require('http-signature');

//STEP2: 此處預計採用utf-8讀ssh key,另外,key是採用SHA256的加密方式
//產生key的指令:ssh-keygen -t rsa
var ENCODE= 'UTF-8';
var alg = "RSA-SHA256";
var n = new Date().toUTCString();
//讀取public key與private key
//public key
var pubKey = fs.readFileSync("/root/.ssh/id_rsa.pub", ENCODE);
//private key
var privKey = fs.readFileSync("/root/.ssh/id_rsa", ENCODE);

//STEP3: 使用base64 sign ssh private key
var signer = crypto.createSign(alg);
signer.update(n);
var secrit = signer.sign(privKey, 'base64');
console.log('SSH key singed...............................................');
console.log(secrit);

//以下部分可以用在server side
//STEP4: 透過http-signature來將public key轉換成pem格式
console.log('Compute SSH key to PEM.......................................');
var pem = hs.sshKeyToPEM(pubKey);
console.log(pem);

//STEP5: 轉換過的pem檔案,就可以透過crypto進行verify
console.log('Start to verify..............................................');
var ver = crypto.createVerify(alg);
ver.update(n);
var v = ver.verify(pem, secrit, 'base64');
console.log(v); //這邊會顯示verify的結果

以上,可以供有需要的人做參考~


2013年3月28日 星期四

15 Lines NodeJS File Server...

Node.js來初始化HTTP協定是相當簡單的事情
下面展示一個簡單的http server範例
可以把執行路徑下的任何檔案當做http資源來瀏覽

    
var fs = require('fs')
  , http = require('http');
http.createServer(function (req, res) {   var path = req.url;
  try{
    var f = fs.readFileSync('.' + path);
    console.log(f);
    console.log(f);
    res.end(f.toString());   } catch(e) {
    console.log(e);
    res.end('');
  }
  }
}).listen(1337); console.log('Server running at http://127.0.0.1:1337/');
目前作者已經包裝成NPM套件
可以透過下面方式安裝與使用(以下擷取自:https://github.com/peihsinsu/noder)

Noder - Simple HTTP Server 

Install

Install using npm...
    # npm install noder -g  

Usage

    # noder  Server running at http://127.0.0.1:1337/  

View

Browser View http://127.0.0.1:1337/test.html (Assump that the test.html exist in the current folder)
    <Buffer 23 21 2f 62 69 6e 2f 62 61 73 68 0a 63 64 20 2f 6f 70 74 0a 23 77 67 65 74 20 68 74 74 70 3a 2f 2f 6e 6f 64 65 6a 73 2e 6f 72 67 2f 64 69 73 74 2f 76 30 ...>  { [Error: ENOENT, no such file or directory './favicon.ico']    errno: 34,    code: 'ENOENT',    path: './favicon.ico',    syscall: 'open' }  <Buffer 1f 8b 08 00 ed 18 e5 50 00 03 ec 3d 6b 77 db 36 b2 f9 5a fd 0a 44 67 cf 4a 4a 25 ea 2d 77 ed 3a 8d 9b b8 4d 77 f3 ba b1 fb b8 27 37 c7 a2 48 c8 62 4c 91 ...>

2013年3月21日 星期四

透過node.js取得request上有用的資訊

身在網路的世界打滾∼有些事情不得不知道...
在node.js中,他把request做了某個程度的wrapper
我們可以透過下面的方法取得一些常用的連線參數
  • 取得server side full url:
    req.url
  • 取得request client的IP位置:
    req.connection.remoteAddress
  • 取得referer page(從哪個網址連線進入)
    req.headers['referer']
  • 取得user agent information:
    req.headers['user-agent']
實際上程式碼可以向這樣:


http.createServer(function (req, res) {
   console.log(req.connection);
   var result = 'req.url:' + req.url + '\r\n';
   result += 'req.connection.remoteAddres:' + req.connection.remoteAddress + '\r\n';
   if(req.headers) {
       result += 'req.headers[\'referer\']:'+ req.headers['referer'] + '\r\n';
       result += 'req.headers[\'user-agent\']:' + req.headers['user-agent'] + '\r\n';
   }
   res.end(result);
}).listen(port, server);


大家可以參考看看∼

2013年2月6日 星期三

Call by value and call by reference of Node.js

Node.js中的變數,屬於call by value的範圍(我猜是原生型別的關係)
下面是範例:

var a = 1;
var b = a;
console.log(a + '::' + b);
> 1::1
b = b + 1;
console.log(a + '::' + b);
> 1::2

上面的b值改變時候,不影響a值,因此a與b無reference關係...

而物件的話,看起來屬於call by reference...

var a = {aa: 111};
var b = a;
console.log(a);
console.log(b);
console.log('===========');
b.aa = 222;
console.log(a);
console.log(b);
>{ aa: 111 }
>{ aa: 111 }
>============
>{ aa: 222 }  //這是a
>{ aa: 222 }  //這是b

上面的b物件改變aa的值時候,實際上影響到a物件的aa值,屬於call by reference
因此在操作時候需要特別小心...
一個不小心....!@#!$!@#


2013年1月20日 星期日

ExpressJS三兩事

ExpressJS應該是學Node.js的開發者必碰的框架,一些基本的說明收錄如下:

專案之初

專案採用ExpressJS之框架建置,建置過程減列如下:

    # mkdir ~/project  # express ~/project/ProjectName  # cd ~/project/ProjectName  # npm install  

目錄結構

  • app.js : 程式進入點
  • views/ : 放置*.ejs檔案,為view module的程式碼位置,亦即與java中的jsp相同地位的程式
  • routes/ : 放置route相關處理的程式碼,預設ExpressJS將app.js中的routing處理都拉到routes/下面
  • public/ : 放置靜態資源的位置
  • node_modules : 透過npm install後,npm會將定義域package.json中的所需函式庫都下載安裝至此

Configure

Igongsha將view engine由預設jade修改為ejs,設定部分主要如下:

    var express = require('express')    , partials = require('express-partials')    ....;    var app = express();    // Initial the layout system in expressjs 3.x  app.use(partials());    app.configure(function(){    //Set listen port     app.set('port', process.env.PORT || 7800);    //Set views' folder    app.set('views', __dirname + '/views');    //Set view engine, we choide ejs here    app.set('view engine', 'ejs');    ...    //Set public folder    app.use(express.static(path.join(__dirname, 'public')));  });    //Set running mode  app.configure('development', function(){    app.use(express.errorHandler());  });    //Set routing (this use the routes middleware, that default use the index.js under $project/routes)  app.get('/', routes.index);  

Routing

Routing簡單的說就是URL存取位置,你可以直接在app.js中寫處理,也可以拉出到middleware中

Under app.js:

    //That can access using http://host:port/test  app.get('/test', function(req, res){    res.end('...');  })  

Or move to middleware:

    //app.js  app.get('/test', routes.test);    //routes/index.js  exports.test = function(req, res){    res.end('...');  }  

Routing Types

ExpressJS依據HTTP method wrapper routing成get, post, del, put, all,說明如下:

  • app.get: HTTP GET傳遞方式,此方式傳遞時,無法使用req.body取值,通常可以作為讀取資料之用
  • app.post: HTTP POST傳遞方式,可以使用req.body取出Form中參數的傳遞,通常可以作為新增資料之用
  • app.del: HTTP DELETE傳遞方式,通常可以作為刪除資料之用
  • app.put: HTTP PUT傳遞方式,通常可以作為更新資料之域
  • app.all: 接受所有HTTP協定,內部可用req.method判斷傳入的Method為何

Middleware

舉凡非view的,通常nodejs稱作middleware,而我習慣說是lib...,一個存放商業邏輯的地方...

  • lib/*.js : 存放moddleware或函式庫或工具的地方
  • routes/*.js : 存放app.js中抽出的routing處理的地方,也可以說是route的middleware
  • node_modules/* : 定義於package.json中的dependency,在npm install後都會被安裝於此

View

頁面程式的產生工廠,類似java中的jsp,可以透過scriptlet的語法'<%- ... %>', '<%= ... %>', '<% ... %>'來嵌入後台程式碼,其中差別說明如下: '<%- ... %>', 用來嵌入不被跳脫(tag的<或>會被轉譯)的程式碼 '<%= ... %>', 用來嵌入需要被跳脫的程式碼 * '<% ... %>', 用來放置運算 views/layout.ejs

    <h1>This is from view/layout.ejs</h1>    <%-body%>    <footer>    <p align="center" style="width:100%">&copy; MiCloud 2013</p>  </footer>  

sample.ejs

    <title><%=title%></title>  Hello <%=user%>  <ul>  <%  for(var i=0; i<10; i++) {  %>  <li>This is ... <%=i%></li>  <%  }  %>  </ul>  

URL Access

已上面app.get('/test', routes.test)為例,伺服器啟動後,就可以使用http://server_ip:port/test來存取routes.test裡面的運算,而參數的存取,可以透過下面幾種方式:

  • req.params.xxx或req.params[xxx]: 如果routing的定義中有使用到:xxx的路徑,例如app.get('/test/:xxx', routes.test)的話,那就可以透過req.params來取xxx的值
  • req.body.xxx: 如果有使用到form的post時候,可以透過req.body.xxx來存取form中id/name=xxx的欄位傳送過來的值
  • query parameters: 如果參數的傳遞是使用url query string來傳遞時候,則可以使用req.url取出url,並透過url.parse()解析url之後,再取出該參數,範例如下:
    var url_parts = url.parse(req.url, true);  var query = url_parts.query;  console.log(query.xx);  

Static Pages

Express中的靜態資源位置,是在一開始的app.configure()中設定的,通常是寫這樣:

      app.use(express.static(path.join(__dirname, 'public')));  

因此,專案Code Gen後的預設目錄一般為public目錄,這些目錄下的檔案會忠實的呈現在routing上,例如$project/public/test.html檔案,會呈現在url:http://server_ip:port/test.html上,而其他靜態資源(image, video, music...)均可以透過這樣的規則放置與存取。