2015年2月15日 星期日

[SQLite] 跨 database (db file) 進行 Table JOIN

使用 SQLITE - Attach 這個指令即可:

$ ls
a.sqlite3 b.sqlite3
$ sqlite3
sqlite> attach 'a.sqlite3' as adb
sqlite> attach 'b.sqlite3' as bdb
sqlite> .tables
adb.user  bdb.data
sqlite> SELECT adb.user.id, adb.user.name, bdb.data.info FROM adb.user, bdb.data WHERE adb.user.id = bdb.data.id

2015年2月14日 星期六

AWS 筆記 - DB Instance XXXX contains MyISAM tables that have not been migrated to InnoDB. These tables can impact your ability to perform point-in-time restores. Consider converting these tables to InnoDB

先查看有哪些 table:

mysql> SELECT TABLE_NAME, ENGINE FROM information_schema.TABLES;
+----------------------+--------------------+
| TABLE_NAME           | ENGINE             |
+----------------------+--------------------+
...
| pma_bookmark         | MyISAM             |
| pma_column_info      | MyISAM             |
| pma_designer_coords  | MyISAM             |
| pma_history          | MyISAM             |
| pma_pdf_pages        | MyISAM             |
| pma_recent           | MyISAM             |
| pma_relation         | MyISAM             |
| pma_table_coords     | MyISAM             |
| pma_table_info       | MyISAM             |
| pma_table_uiprefs    | MyISAM             |
| pma_tracking         | MyISAM             |
| pma_userconfig       | MyISAM             |
...


結果發現是 PHPMyAdmin 的那些 tables,由於這些影響不大,就操刀吧!以 pma_bookmark 為例

mysql> ALTER TABLE  `phpmyadmin`.`pma_bookmark` ENGINE = INNODB;

收工。

Call Facebook API without token at Linode: error: message: Application request limit reached

昨晚開了一台 Linode Server,想說來研究一下 Facebook api,結果:

$ curl "https://graph.facebook.com/fql?q=SELECT%20total_count%20FROM%20link_stat%20WHERE%20url%20='www.google.com'"
{"error":{"message":"(#4) Application request limit reached","type":"OAuthException","code":4}}


不死心,發 ticket 抱怨一下,想說會不會前一個用戶太操,得到了免費換了 IP 。結果仍是一樣的。接著,想起有美國的機器,測了一下仍是如此。

幾番測試後,我猜 Linode IP Range 大概被關注很久,預設都不給用,看來人紅也是種困擾 XD

以上 command 在任何一台的機器,預期得到的正確結果為:

$ curl "https://graph.facebook.com/fql?q=SELECT%20total_count%20FROM%20link_stat%20WHERE%20url%20='www.google.com'"
{"data":[{"total_count":10366203}]}

2015年2月12日 星期四

AWS 筆記 - 使用 AWS Glacier 服務備份大量資料 @ Ubuntu 14.04

這個服務大概 2014 年夏天就開始關注並且在秋天嘗試使用,曾經也寫過一篇筆記但...最後沒發表 XD 實在是 AWS Glacier 如其名,大部份的指令真的像冰河緩慢移動 Orz 接著忙了就忘了。這次下定決心來寫一篇筆記。

簡言之,費用比 AWS S3 便宜,但是存取 AWS Glacier 的行為更像傳統磁帶模式,很多操作動作,會先給你一個 Job ID,還得手動用此 ID 去確認結果。例如想查閱已經有多少檔案,會發一個需求 Job ID 給你,而非馬上跟你說已經有多少檔案了。

整體上,要上傳資料一定要走 AWS API 方式,也就是到 AWS IAM 上建立一個 user,給予以下權限:
  • Amazon Glacier Full Access (另一個則是 Amazon Glacier Read Only Access)
  • Amazon SQS Full Access (下載檔案會用到, 若工作僅上傳則不需要, 沒有時的錯誤訊息: Access to the resource https://sqs.ap-northeast-1.amazonaws.com/ is denied)
  • Amazon SNS Full Access (下載檔案會用到, 若工作僅上傳則不需要, 沒有時的錯誤訊息: User: arn:aws:iam::####:user/#### is not authorized to perform: SNS:CreateTopic on resource)
我記得去年摸時,是使用 Amazon SimpleDB (sdb:*) 相關的權限,印象中跟 metadata 有關,不過現在卻沒查到了?! :P 接著,替使用者建立一組 access key/ secret key 來使用,而往後的上傳、下載等是靠這組 API KEY 工作。

此外,使用 AWS Glacier 前,要稍微瞭解一下操作方式
  • 不同的 Data Center 會因為電價等關係,所以儲存的費用不一樣。
  • 上傳資料前,除了要挑選 Data Center 外,還需要類似建立一個類似目錄的儲存單位 (Vault)
  • 除了網頁版 GUI 可以進行 Create Vault, Delete Vault 外,其餘都一律透過 API 進行,其中 Delete Vault 還必須確定裡頭沒其他檔案
  • 透過 API 操作時,需要的基本參數為 API KEY、Data Center (region/endpoint) 等資料
雖然用過 python 版工具 https://github.com/uskudnik/amazon-glacier-cmd-interface,這次就來用用 Java 版吧!https://github.com/MoriTanosuke/glacieruploader

建立 Vault (可透過 AWS Web Console)操作:

$ java -jar uploader-0.0.8-SNAPSHOT-jar-with-dependencies.jar -e "https://glacier.ap-northeast-1.amazonaws.com" -v changyy-vault -c
INFO  Using end point: https://glacier.ap-northeast-1.amazonaws.com
INFO  Creating vault changyy-vault...
INFO  Vault changyy-vault created. {Location: /##########/vaults/changyy-vault}
LastInventoryDate: null
NumberOfArchives: 0
SizeInBytes: 0
VaultARN: arn:aws:glacier:ap-northeast-1:##########:vaults/changyy-vault
VaultName: changyy-vault


上傳檔案(最後的 archive 接的資料就是該筆料的 ID):

$ java -jar uploader-0.0.8-SNAPSHOT-jar-with-dependencies.jar -e "https://glacier.ap-northeast-1.amazonaws.com" -v changyy-vault --upload ~/uploader-0.0.8-SNAPSHOT-jar-with-dependencies.jar
INFO  Using end point: https://glacier.ap-northeast-1.amazonaws.com
INFO  Starting to upload $HOME/uploader-0.0.8-SNAPSHOT-jar-with-dependencies.jar to vault changyy-vault...
INFO  Uploaded archive ########################################


切檔上傳,此例是 128MB 為單位,適合檔案很大的情境(Archive ID 接的資料就是該筆料的 ID):

$ java -jar uploader-0.0.8-SNAPSHOT-jar-with-dependencies.jar -e "https://glacier.ap-northeast-1.amazonaws.com" -v changyy-vault --upload ~/uploader-0.0.8-SNAPSHOT-jar-with-dependencies.jar --multipartupload ~/TargetBigFile --partsize 134217728
INFO  Using end point: https://glacier.ap-northeast-1.amazonaws.com/
INFO  Multipart uploading TargetBigFile to vault changyy-vault with part size 134217728 (128.00MB).
INFO  Upload ID (token): ################################################
INFO  Part 1/187 (bytes 0-134217727/*) uploaded, checksum: e19319be5e3c5d3f45a1ce7ef9ab3644b6933ec01c0754285babf45eb46b5b0b
...
INFO  Part 187/187 (bytes 24964497408-24993715534/*) uploaded, checksum: d0219f53b4f54431495211bfd8880fe52597354acc51aa077dcb67cacee69f53
INFO  Uploaded Archive ID: ################################################
INFO  Local Checksum: a1500723e11892cc2bb297d5d6f97a08035e30810ae0e3342184fbed4e2c2d5b
INFO  Remote Checksum: a1500723e11892cc2bb297d5d6f97a08035e30810ae0e3342184fbed4e2c2d5b
INFO  Checksums are identical, upload succeeded.


然而,剛上傳完是無法馬上下載的 :P 而想要查詢檔案列也是,必須先發一個"查詢列表"的工作(得到 Job ID),等工作結束後才能查詢到結果(取得檔案列表)

發出"查詢 Vault 檔案列表"的需求:

$ java -jar uploader-0.0.8-SNAPSHOT-jar-with-dependencies.jar -e "https://glacier.ap-northeast-1.amazonaws.com" -v changyy-vault -l
INFO  Using end point: https://glacier.ap-northeast-1.amazonaws.com
INFO  Starting inventory listing for vault changyy-vault...
INFO  Inventory Job created with ID
8KDBk2AS_9bYC8dIOBHxjitqxaLhEklXPfU6jZO-t-su3cp1k3NaHFIUpFaBiJDXDGFyzYyqaw-3MboGNlJ2W6kKDzmt


若這個 Vault 是剛建立的,還會有類似錯誤訊息:vaults/changyy-vault cannot be initiated yet, as Amazon Glacier has not yet generated an initial inventory for this vault.

取得"查詢 Vault 檔案列表"的結果:

$ java -jar uploader-0.0.8-SNAPSHOT-jar-with-dependencies.jar -e "https://glacier.ap-northeast-1.amazonaws.com" -v changyy-vault -l 8KDBk2AS_9bYC8dIOBHxjitqxaLhEklXPfU6jZO-t-su3cp1k3NaHFIUpFaBiJDXDGFyzYyqaw-3MboGNlJ2W6kKDzmt

若工作未做完,會顯示錯誤訊息:ERROR The job is not currently available for download。做完的話,會顯示清單,其中 Description 在這套 Java 工具下,會自動填寫上傳的檔名:

ARN: arn:aws:glacier:ap-northeast-1:##############:vaults/changyy-vault
------------------------------------------------------------------------------
Description:  uploader-0.0.8-SNAPSHOT-jar-with-dependencies.jar
Archive ID: q_SfW7MNmTE1_9xBbmzP5MvnEGYYmF8wCIe2aYs4_7NAXjn8fEO4nl97QZ-deJ_hDsKni7n5z0avn8gEdAnFfzMV4xE9FlF2Fr3UualyZj0b4LNSq9cENWYWoueSma9Kq8zGuwA9IA
CreationDate: 2015-02-07T11:17:36Z
Size: 19496656 (18.60MB)
SHA: d07cddbcbe3a83dba2b4ca654760bba4b77f92ae1ecc9f1fbffad337730fece0


下載檔案:

$ java -jar uploader-0.0.8-SNAPSHOT-jar-with-dependencies.jar -e "https://glacier.ap-northeast-1.amazonaws.com" -v changyy-vault --download q_SfW7MNmTE1_9xBbmzP5MvnEGYYmF8wCIe2aYs4_7NAXjn8fEO4nl97QZ-deJ_hDsKni7n5z0avn8gEdAnFfzMV4xE9FlF2Fr3UualyZj0b4LNSq9cENWYWoueSma9Kq8zGuwA9IA --target /tmp/test.jar
INFO  Using end point: https://glacier.ap-northeast-1.amazonaws.com
INFO  Downloading archive q_SfW7MNmTE1_9xBbmzP5MvnEGYYmF8wCIe2aYs4_7NAXjn8fEO4nl97QZ-deJ_hDsKni7n5z0avn8gEdAnFfzMV4xE9FlF2Fr3UualyZj0b4LNSq9cENWYWoueSma9Kq8zGuwA9IA from vault changyy-vault...
INFO Archive downloaded to /tmp/test.jar


整個過程不會馬上進入下載 Orz 例如我下載一個 52MB 的檔案,整個過程耗費 245 分鐘...絕對不是下載速度太慢,而是準備流程要等好一陣子。

刪除檔案:

$ java -jar uploader-0.0.8-SNAPSHOT-jar-with-dependencies.jar -e "https://glacier.ap-northeast-1.amazonaws.com" -v changyy-vault --delete q_SfW7MNmTE1_9xBbmzP5MvnEGYYmF8wCIe2aYs4_7NAXjn8fEO4nl97QZ-deJ_hDsKni7n5z0avn8gEdAnFfzMV4xE9FlF2Fr3UualyZj0b4LNSq9cENWYWoueSma9Kq8zGuwA9IA
INFO  Using end point: https://glacier.ap-northeast-1.amazonaws.com
INFO  Deleting archive q_SfW7MNmTE1_9xBbmzP5MvnEGYYmF8wCIe2aYs4_7NAXjn8fEO4nl97QZ-deJ_hDsKni7n5z0avn8gEdAnFfzMV4xE9FlF2Fr3UualyZj0b4LNSq9cENWYWoueSma9Kq8zGuwA9IA from vault changyy-vault...
INFO  Archive q_SfW7MNmTE1_9xBbmzP5MvnEGYYmF8wCIe2aYs4_7NAXjn8fEO4nl97QZ-deJ_hDsKni7n5z0avn8gEdAnFfzMV4xE9FlF2Fr3UualyZj0b4LNSq9cENWYWoueSma9Kq8zGuwA9IA deletion started from vault changyy-vault.


刪除 Vault:

$ java -jar uploader-0.0.8-SNAPSHOT-jar-with-dependencies.jar -e "https://glacier.ap-northeast-1.amazonaws.com" -v changyy-vault --delete-vault
INFO  Using end point: https://glacier.ap-northeast-1.amazonaws.com
INFO  Deleting vault changyy-vault...


若 vault 內還有檔案會有錯誤訊息:Vault not empty or recently written to: arn:aws:glacier:ap-northeast-1:############:vaults/changyy-vault。此外,若先去刪檔案,再來執行也會有一樣的問題,因為這是冰川啊 XD 刪檔也是慢慢地

整體心得,AWS Glacier 操作上真的很煩,因為太慢了。此外,也必須把那些 File Archive ID 記好,或是任何工作的 Job ID 記好,後續才能工作。有興趣可以在玩看看視窗介面,例如 CrossFTP 等,在操作檔案列表時,會跟你說要數小時(>5小時)才會得知結果,唯一的好處就是 CrossFTP 會幫你把一些 Job ID 記住吧

2015年2月9日 星期一

使用 Openssl / C++ Crypto++ (Cryptopp) 進行 AES-128 / AES-256 Encryption @ Ubutnu 14.04

去年在一些服務上有用到 AES Encryption,當時是用 PHP 處理的 :P 最近想說 openssl 很威,練一下好了 XD 然而 AES 有很多模式 Orz 直接用 openssl -h 就可以觀看

$ openssl -h
aes-128-cbc       aes-128-ecb       aes-192-cbc       aes-192-ecb    
aes-256-cbc       aes-256-ecb       base64            bf              
bf-cbc            bf-cfb            bf-ecb            bf-ofb          
camellia-128-cbc  camellia-128-ecb  camellia-192-cbc  camellia-192-ecb
camellia-256-cbc  camellia-256-ecb  cast              cast-cbc        
cast5-cbc         cast5-cfb         cast5-ecb         cast5-ofb      
des               des-cbc           des-cfb           des-ecb        
des-ede           des-ede-cbc       des-ede-cfb       des-ede-ofb    
des-ede3          des-ede3-cbc      des-ede3-cfb      des-ede3-ofb    
des-ofb           des3              desx              idea            
idea-cbc          idea-cfb          idea-ecb          idea-ofb        
rc2               rc2-40-cbc        rc2-64-cbc        rc2-cbc        
rc2-cfb           rc2-ecb           rc2-ofb           rc4            
rc4-40            seed              seed-cbc          seed-cfb        
seed-ecb          seed-ofb          zlib


一開始還真不知要挑個 :P 並且用 openssl 加密出來,在其他程式語言卻解不出來 Orz

$ echo -n "Hello World" | openssl aes-128-cbc -e -k "password" -out /tmp/output
$ openssl aes-128-cbc -d -k "password" -in /tmp/output
Hello World


後來才找到這篇文章:
openssl: recover key and IV by passphrase
http://security.stackexchange.com/questions/29106/openssl-recover-key-and-iv-by-passphrase,講得非常清楚,簡言之:

The encryption format used by OpenSSL is non-standard: it is "what OpenSSL does", and if all versions of OpenSSL tend to agree with each other, there is still no reference document which describes this format except OpenSSL source code.

例如加上 -P 可以印出細部訊息:

$ openssl aes-128-cbc -e -k "password" -P
salt=EDC6E641C29F08F0
key=2CBD7689AEB5880E13803871A1DCDDD5
iv =FFFFBF58B814E180882029109B437D74


每次執行 salt, key 和 iv 都會一直變動,所以,若要用 Openssl 驗證時,需要一口氣填好 key 跟 iv 資訊:

$ openssl aes-128-cbc -e -K '' -iv '' -P
salt=0100000000000000
key=00000000000000000000000000000000
iv =00000000000000000000000000000000


當指定 -K 跟 -iv 時,就不會出現亂跳的情況,同理,在其他程式語言(此例以 C++ 為例),就能夠順利加解密。別忘了 -K 跟 -iv 需要 HEX String 格式的參數,在 Unix-like 系統可以透過 echo, od 跟 sed 來辦事:

$ echo -n "0123456789012345" | od -A n -t x1 | sed 's/ //g'
30313233343536373839303132333435
$ openssl aes-128-cbc -e -K `echo -n "0123456789012345" | od -A n -t x1 | sed 's/ //g'` -iv '' -P
salt=0100000000000000
key=30313233343536373839303132333435
iv =00000000000000000000000000000000


別忘了,若是要用 AES-256 時,Key 要記得手動接好 XD

$  echo -n "01234567890123456789012345678901" | od -A n -t x1 | sed 's/ //g'
30313233343536373839303132333435
36373839303132333435363738393031

$ openssl aes-256-cbc -e -K 3031323334353637383930313233343536373839303132333435363738393031 -iv '' -P
salt=0100000000000000
key=3031323334353637383930313233343536373839303132333435363738393031
iv =00000000000000000000000000000000


接著,來寫一點 C++ 吧:

#include <iostream>
#include <fstream>
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <cryptopp/filters.h>
// http://www.cryptopp.com/
// sudo apt-get install libcrypto++-dev
// $ g++ main.cpp -lcryptopp

int main(int argc, char **argv) {
        byte key[ CryptoPP::AES::DEFAULT_KEYLENGTH ], iv[ CryptoPP::AES::BLOCKSIZE ];
        memset( key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH );
        memset( iv, 0x00, CryptoPP::AES::BLOCKSIZE );

        for (int i=0 ; i<CryptoPP::AES::DEFAULT_KEYLENGTH ; ++i)
                key[i] = ('0' + (i%10) ) ;

        std::cout << "block size: " << CryptoPP::AES::BLOCKSIZE << std::endl;
        std::cout << "key(" << CryptoPP::AES::DEFAULT_KEYLENGTH << "):[" << key << "]" << std::endl;

        std::string plaintext = "Hello world. To man to be a better man.";
        std::string ciphertext;

        // enc
        CryptoPP::AES::Encryption aesEncryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
        CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption( aesEncryption, iv );
        CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink( ciphertext ) );
        stfEncryptor.Put( reinterpret_cast<const unsigned char*>( plaintext.c_str() ), plaintext.length());
        stfEncryptor.MessageEnd();

        std::ofstream output ("/tmp/output");
        output << ciphertext ;
        output.close();

        // dec
        std::string decryptedtext;
        CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
        CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv );
        CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decryptedtext ) );
        stfDecryptor.Put( reinterpret_cast<const unsigned char*>( ciphertext.c_str() ), ciphertext.size() );
        stfDecryptor.MessageEnd();

        std::cout << "dec: [" << decryptedtext << "]" << std::endl;

        return 0;
}


執行完的產出在 /tmp/output,可以再用 openssl 把它解回來,而上述範例的 Key 長度為 16 ,因此適用於 aes-128-CBC,若想要用 aes-256-cbc 僅需把 Key 的長度調整為 32 即可搞定 :P

$ g++ t.cpp -lcryptopp
$ ./a.out
block size: 16
key(16):[0123456789012345]
dec: [Hello world. To man to be a better man.]
$ openssl aes-128-cbc -d -K `echo -n '0123456789012345' | od -A n -t x1 | sed 's/ //g'` -iv '' -in /tmp/output
Hello world. To man to be a better man.

[Linux] 透過 echo, od, sed 將字串轉 HEX String @ Ubuntu 14.04

用法:

$ echo -n "0123456789" | od -A n -t x1 | sed 's/ /\\x/g'
\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39

$ echo -n "你好嗎" | od -A n -t x1 | sed 's/ /\\x/g'
\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x97\x8e

2015年2月7日 星期六

當小傑奇犽離開雲古時...

很久沒寫一點內心戲了?不知不覺已在業界打滾五年多了? coding 早已破十來年。最近回顧起身旁的強者我同學、學弟,都開始挑選不一樣的人生道路行走,甚至回憶起過往點滴,都會驚覺當年真的握有一手好牌啊,可惜事過境遷,錯過了,就很難相聚,更別說再一同打拼。

夜深時,泡杯咖啡,不禁意地想起,原來當年的彼此都是很不錯的,套句愛情老台詞:在錯誤的時間點(失敗的案子),遇上對的人(爆強的工程師)?

人總會成長,強者更是跳躍,環境永遠是重要的因素 (孟母也略懂三遷),就像獵人漫畫的情節,小傑奇犽終究離開了雲古。

大家仍舊繼續成長,用著彼此不熟悉的步調或價值觀,世界也因亂度增加而美好!我想,越來越期待偶爾的吃飯相聚了 XD

2015年2月5日 星期四

[VB] 透過 Macro (巨集) 亂數挑選句子 @ Microsoft Powerpoint / OpenOffice Impress

前幾天接到朋友的一個需求,我想了一會覺得應該不難,就下海摸索一下,使用情境如下:

活動中讓賓客可以跟一些世界名句拍照合影(例如七言絕句等),希望每個賓客都可以透過抽籤(亂數)機制跟不同句子拍照。

分析一下技術:
  • 亂數功能
  • 有一個文字區域,每次亂數得到的結果要更新在文字區
原本朋友是說用網頁也行,但我覺得活動場所要連網路好像有點危險(雖然純HTML+JS也能離線),於是乎還是來用用投影片模式 XD 方向:試試看巨集吧!

簡言之,以 Microsoft Office 2007 / OpenOffice Impress 為例,亂數用法:

Public Function chooseWords As String
Dim MyArray As Variant

REM *** Comment ***
MyArray = Array("懶人包", "天龍人", "卡卡獸", "給開司一罐啤酒", "完全沒有××", "數學老ㄙ常請假", "天大地大臺科大","雅量背影出師表")

REM *** Random ***
ArraySize = UBound(MyArray)
index = Int(Rnd * ArraySize ) + 1

REM *** Return
chooseWords = MyArray(index)
REM MSGBox(MyArray(index))
End Function


至於更換掉投影片內的文字框,以 OpenOffice Impress 為例,假定投影片只有第一張,且只有一個文字框:

Sub Main
Dim Doc As Object
Dim SlideList as Object
Dim Slide AS Object
Dim Target As Object

Doc = ThisComponent
SlideList = Doc.getDrawPages()
Slide = SlideList.getByIndex(0)
Target = Slide.getByIndex(0)
REM MSGBox(chooseWords())
Target.setString( chooseWords() )
End Sub


以 Microsoft Office 2007 - Powerpoint 為例:

Sub Main()
    For Each sld In ActivePresentation.Slides
        For Each sh In sld.Shapes
            Rem MsgBox sh.Type
            If sh.Type = msoPlaceholder Or sh.Type = msoTextBox Then
                sh.TextFrame.TextRange.Text = chooseWords()
            End If
        Next
    Next
End Sub


上述 Microsoft 文件比較豐富(至少對沒經驗的我來說比較快找到),發現可以判斷物件的型態( msoPlaceholder 和 msoTextBox )。

最後則是事件綁定,例如在什麼事件下,呼叫巨集(Macro: Main) ,在 Microsoft Office - PowerPoint 方面,發現在插入圖片後,點擊圖片時,可以替他增加"動作",這時就可以輕鬆綁定巨集,至於 OpenOffice Impress 的部分...由於需求解掉,就沒再繼續鑽了。