-
Notifications
You must be signed in to change notification settings - Fork 18
/
Server.js
159 lines (130 loc) · 5.11 KB
/
Server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
var fs = require('fs-extra');
var forge = require('node-forge');
var onlyPath = require('path');
var LinvoDB = require("linvodb3");
var zip = new require('node-zip')();
rootData = "/Users/guest/Library/Containers/com.readmoo.readmoodesktop/Readmoo/";
pathBook = "/Users/guest/Library/Containers/com.readmoo.readmoodesktop/Readmoo/api/book/"
localStoragePath = "/Users/guest/Library/Application Support/Readmoo/Local Storage/app_readmoo_0.localstorage";
LinvoDB.defaults.store = { db: require("medeadown") };
LinvoDB.dbPath = "./db/";
var encryptionDB = new LinvoDB("encryption", {}, {});
var encryptionMethods = {
/*'http://www.idpf.org/2008/embedding': this.embeddedFontDeobfuscateIdpf,
'http://ns.adobe.com/pdf/enc#RC': this.embeddedFontDeobfuscateAdobe,*/
'http://www.w3.org/2001/04/xmlenc#aes128-cbc': aes256Decrypt //actually use aes256-cbc
};
// Get Pem
var sqlite = require('better-sqlite3');
var lsDB = new sqlite(localStoragePath);
var localStorageDatas = lsDB.prepare("SELECT value FROM ItemTable WHERE key = 'rsa_privateKey'").all();
var mypem = localStorageDatas[0].value;
mypem = mypem.toString().replace(/(\r\n|\n|\r)/gm, "");
console.log(mypem);
function aes256Decrypt(aesKey, fetchCallback, input, file, path){
var iv = input.slice(0,16),
ciphertext = input.slice(16),
decipher = forge.cipher.createDecipher('AES-CBC', aesKey),
// 2017/09/25 修正取得副檔名的方式
type = file.split('.').pop();
decipher.start({iv: iv});
decipher.update(forge.util.createBuffer(ciphertext, 'binary'));
decipher.finish(function(){ });
var output = decipher.output;
var padding_length = output.last();
var plaintextBuffer = output.truncate(padding_length);
if (type !== 'css') {
var nodeBuffer = new Buffer(plaintextBuffer.getBytes(), 'binary');
fetchCallback(nodeBuffer, plaintextBuffer.length());
} else {
fetchCallback(plaintextBuffer.toString(), plaintextBuffer.length());
}
}
var decryptDocument = function(encryptionInfo, retrivalObj, input, file, path, fetchCallback) {
// 2016/07/14 不支援就直接回傳空內容
if (!retrivalObj) {
fetchCallback("", 0);
return
}
var cipher = retrivalObj.cipher
pki = forge.pki
kpr_pem = mypem
kpr = pki.privateKeyFromPem(kpr_pem)
ciphertext = forge.util.decode64(cipher)
aesKey = kpr.decrypt(ciphertext)
//TODO get decipher from Buffer directly
encryptionAlgorithm = encryptionMethods[encryptionInfo.encryptionAlgorithm];
//console.log("AESKEY: ", aesKey);
if(encryptionAlgorithm)
encryptionAlgorithm.call(this, aesKey, fetchCallback, input, file, path);
else
console.log('not support this aes decryption mode yet');
};
var getRetrivalMethod = function (encryptionTable, RSA_id){
// RSA_id = #EK 之類的
for (var i=0; i< encryptionTable.rsakey.length; i++){
// console.log('encryptionTable.rsakey[i].id: ' + encryptionTable.rsakey[i].id);
if(RSA_id === encryptionTable.rsakey[i].id){
//return cipherdata to rsa decode
return {
'algorithm': encryptionTable.rsakey[i].algorithm,
'cipher': encryptionTable.rsakey[i].cipher
//TODO decipher Buffer
};
}
}
};
var openEncrypedBook = function(bookid, encryptedPath, encryptionTable, saveFile){
var encryptionPath,
encryptedPath,
encryptionInfo,
retrivalObj,
_path = pathBook;
encryptionPath = pathBook + bookid + '/META-INF/'+'encryption.xml';
_path += bookid + '/' + encryptedPath; // osx32/64
encryptionInfo = encryptionTable.encryptions[encryptedPath];
if (encryptionInfo)
retrivalObj = getRetrivalMethod(encryptionTable, encryptionInfo.RSA_ID);
var input = fs.readFileSync(_path, {encoding: 'binary'});
decryptDocument(encryptionInfo, retrivalObj, input, encryptedPath, _path, function(decryptedData, length){
//存回檔案
saveFile(decryptedData, bookid, encryptedPath);
});
};
var decipherBook = function(bookid, encryptionTable, files) {
var dir = process.cwd() + "/books/" + bookid;
fs.copySync(pathBook+bookid, dir)
var saveFile = function(data, bookid, path) {
saveFilePath = dir+"/"+path;
targetDir = onlyPath.dirname(saveFilePath);
try {
fs.mkdirSync(targetDir, { recursive: true });
} catch (e) {};
fs.writeFile(saveFilePath, data, function(err) {
if(err) {
return console.log(err);
}
});
};
for (var key in files) {
openEncrypedBook(bookid, key, encryptionTable, saveFile);
}
};
var getTableOfBooks = function(){
encryptionDB.find({}, function(err, docs){
docs.forEach(function(doc){
encryptionTable = JSON.parse(doc.table);
var bookid, files;
bookid = encryptionTable.bookid;
files = encryptionTable.encryptions;
decipherBook(bookid, encryptionTable, files);
});
});
};
var bookDir = process.cwd() + "/books"
if (!fs.existsSync(bookDir)){
fs.mkdirSync(bookDir);
}
getTableOfBooks();
// Delete encryption.xml
// Zip the files and rename it to *.epub