Commit 3e505df4 authored by Ivanq's avatar Ivanq

Use libraries from ZeroLib

parent a01557c3
......@@ -51,8 +51,8 @@
</p>
</div>
<script type="text/javascript" src="../js/ZeroFrame.js"></script>
<script type="text/javascript" src="../js/ZeroPage.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroFrame.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroPage.js"></script>
<script type="text/javascript" src="../js/root.js"></script>
</body>
</html>
\ No newline at end of file
......@@ -127,8 +127,8 @@
<div class="info"></div>
<script type="text/javascript" src="../js/ZeroFrame.js"></script>
<script type="text/javascript" src="../js/ZeroPage.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroFrame.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroPage.js"></script>
<script type="text/javascript" src="../js/root.js"></script>
</body>
</html>
\ No newline at end of file
......@@ -60,8 +60,8 @@
</ul>
</main>
<script type="text/javascript" src="js/ZeroFrame.js"></script>
<script type="text/javascript" src="js/ZeroPage.js"></script>
<script type="text/javascript" src="ZeroLib/ZeroFrame.js"></script>
<script type="text/javascript" src="ZeroLib/ZeroPage.js"></script>
<script type="text/javascript" src="js/repo.js"></script>
<script type="text/javascript" src="js/main.js"></script>
<script type="text/javascript" src="js/root.js"></script>
......
......@@ -42,11 +42,11 @@
<div id="repos"></div>
</main>
<script type="text/javascript" src="../js/ZeroFrame.js"></script>
<script type="text/javascript" src="../js/ZeroPage.js"></script>
<script type="text/javascript" src="../js/ZeroFS.js"></script>
<script type="text/javascript" src="../js/ZeroAuth.js"></script>
<script type="text/javascript" src="../js/ZeroDB.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroFrame.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroPage.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroFS.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroAuth.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroDB.js"></script>
<script type="text/javascript" src="js/main.js"></script>
<script type="text/javascript" src="../js/root.js"></script>
</body>
......
......@@ -73,11 +73,11 @@
<a class="button button-blue" id="install">Create</a>
</main>
<script type="text/javascript" src="../js/ZeroFrame.js"></script>
<script type="text/javascript" src="../js/ZeroPage.js"></script>
<script type="text/javascript" src="../js/ZeroFS.js"></script>
<script type="text/javascript" src="../js/ZeroAuth.js"></script>
<script type="text/javascript" src="../js/ZeroDB.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroFrame.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroPage.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroFS.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroAuth.js"></script>
<script type="text/javascript" src="../ZeroLib/ZeroDB.js"></script>
<script type="text/javascript" src="../js/pako.js"></script>
<script type="text/javascript" src="../js/sha.js"></script>
<script type="text/javascript" src="../js/git.js"></script>
......
class ZeroAuth {
constructor(page, acceptedDomains) {
if(typeof page != "object" || !page instanceof ZeroPage) {
throw new Error("page should be an instance of ZeroPage");
}
this.page = page;
if(acceptedDomains) {
if(typeof acceptedDomains != "object" || !acceptedDomains instanceof Array) {
throw new Error("acceptedDomains should be an instance of Array");
}
this.acceptedDomains = acceptedDomains;
} else {
this.acceptedDomains = ["zeroid.bit"];
}
this.activeAuth = null;
this.page.cmd("siteInfo").then(siteInfo => {
if(siteInfo.cert_user_id) {
this.activeAuth = {
user: siteInfo.cert_user_id,
address: siteInfo.auth_address
};
}
});
}
getAuth() {
return this.activeAuth;
}
getAuthAsync() {
return this.page.getSiteInfo()
.then(siteInfo => {
if(siteInfo.cert_user_id) {
return {
user: siteInfo.cert_user_id,
address: siteInfo.auth_address
};
} else {
return null;
}
});
}
requestAuth() {
if(this.activeAuth !== null && this.activeAuth !== undefined) {
return Promise.resolve(this.activeAuth);
} else {
return new Promise((resolve, reject) => {
this.page.once("setSiteInfo", () => {
ZeroPage.async.setTimeout(200)
.then(() => {
return this.page.getSiteInfo();
}).then(siteInfo => {
if(siteInfo.cert_user_id !== null && siteInfo.cert_user_id !== undefined) {
this.activeAuth = {
user: siteInfo.cert_user_id,
address: siteInfo.auth_address
};
resolve(this.activeAuth);
} else {
this.activeAuth = null;
reject("User rejected to authorizate");
}
});
});
this.page.cmd("certSelect", {
accepted_domains: this.acceptedDomains
});
});
}
}
isValidAddress(address) {
return address.indexOf("@") != -1 && // has @
address.indexOf("@", address.indexOf("@") + 1) == -1; // only one @
}
addressToFilename(address) {
if(!this.isValidAddress(address)) return "";
return address.replace(/^(.*)@(.*)/, "[$1]$2");
}
};
\ No newline at end of file
class ZeroDB {
constructor(page) {
if(typeof page != "object" || !page instanceof ZeroPage) {
throw new Error("page should be an instance of ZeroPage");
return;
}
this.page = page;
this.fs = new ZeroFS(page);
this.auth = new ZeroAuth(page);
}
query(query, placeholders) {
return this.page.cmd("dbQuery", [query, placeholders])
.then(result => {
if(result.error) {
return Promise.reject(result.error);
}
return result;
});
}
getPrivateKey(contentFile) {
let auth = this.auth.getAuth();
return this.page.cmd("fileRules", [contentFile])
.then(rules => {
if(auth && rules.signers.indexOf(auth.address) > -1) {
return null;
}
return "stored";
});
}
insertRow(dataFile, contentFile, table, row, autoIncrement) {
let privatekey;
return this.getPrivateKey(contentFile)
.then(p => {
privatekey = p;
return this.fs.readFile(dataFile);
})
.then(data => {
return JSON.parse(data);
}, () => {
return {};
})
.then(data => {
if(typeof data[table] != "object" || !(data[table] instanceof Array)) {
data[table] = [];
}
if(autoIncrement) {
if(!data[autoIncrement.source]) {
data[autoIncrement.source] = 0;
}
row[autoIncrement.column] = data[autoIncrement.source]++;
}
data[table].push(row);
return this.fs.writeFile(dataFile, JSON.stringify(data, null, 4));
})
.then(() => {
return this.page.cmd(
"siteSign",
[
privatekey, // private key
contentFile // file to sign
]
);
})
.then(() => {
this.page.cmd(
"sitePublish",
[
privatekey, // private key
contentFile, // file to publish
false // sign before publish
]
);
return row;
});
}
changeRow(dataFile, contentFile, table, f) {
let privatekey;
return this.getPrivateKey(contentFile)
.then(p => {
privatekey = p;
return this.fs.readFile(dataFile);
})
.then(data => {
return JSON.parse(data);
}, () => {
return {};
})
.then(data => {
if(typeof data[table] != "object" || !(data[table] instanceof Array)) {
data[table] = [];
}
data[table] = data[table].map(f);
return this.fs.writeFile(dataFile, JSON.stringify(data, null, 4));
})
.then(() => {
return this.page.cmd(
"siteSign",
[
privatekey, // private key
contentFile // file to sign
]
);
})
.then(() => {
this.page.cmd(
"sitePublish",
[
privatekey, // private key
contentFile, // file to publish
false // sign before publish
]
);
});
}
changePair(dataFile, contentFile, table, key, value) {
let privatekey;
return this.getPrivateKey(contentFile)
.then(p => {
privatekey = p;
return this.fs.readFile(dataFile);
})
.then(data => {
return JSON.parse(data);
}, () => {
return {};
})
.then(data => {
if(typeof data[table] != "object") {
data[table] = {};
}
data[table][key] = value;
return this.fs.writeFile(dataFile, JSON.stringify(data, null, 4));
})
.then(() => {
return this.page.cmd(
"siteSign",
[
privatekey, // private key
contentFile // file to sign
]
);
})
.then(() => {
this.page.cmd(
"sitePublish",
[
privatekey, // private key
contentFile, // file to publish
false // sign before publish
]
);
});
}
getJsonID(path, version) {
let where;
if(version == 1) {
where = {
path: path
};
} else if(version == 2) {
path = path.split("/");
where = {
directory: path.slice(0, -1).join("/"),
file_name: path.slice(-1)[0]
};
} else if(version == 3) {
path = path.split("/");
where = {
site: path[0],
directory: path.slice(1, -1).join("/"),
file_name: path.slice(-1)[0]
};
}
return this.query("SELECT * FROM json WHERE ?", where)
.then(json => {
return json.length ? json[0].json_id : -1;
});
}
};
\ No newline at end of file
class ZeroFS {
constructor(page) {
if(typeof page != "object" || !page instanceof ZeroPage) {
throw new Error("page should be an instance of ZeroPage");
}
this.page = page;
}
fileExists(file) {
if(file == "") { // root
return Promise.resolve(true); // the following check will fail for root
}
let dirPath = file.split("/").slice(0, -1).join("/");
let basePath = file.split("/").pop();
return this.readDirectory(dirPath)
.then(children => {
return Promise.resolve(children.indexOf(basePath) > -1);
});
}
readFile(file, bytes, required) {
return this.page.cmd("fileGet", [
file, // file
required, // required (wait until file exists)
"base64", // text or base64
300 // timeout
]).then(res => {
if(res === null || res === false) {
return Promise.reject("File doesn't exist: " + file);
} else {
return Promise.resolve(this.fromBase64(res, bytes));
}
});
}
writeFile(file, content, bytes) {
return this.page.cmd("fileWrite", [
file, // file
this.toBase64(content, bytes), // base64-encoded content
true // ignore bad files
]).then(res => {
if(res === "ok") {
return Promise.resolve(file);
} else {
return Promise.reject(res);
}
});
}
deleteFile(file) {
return this.page.cmd("fileDelete", [
file // file
]).then(res => {
if(res === "ok") {
return Promise.resolve(file);
} else {
return Promise.reject(res);
}
});
}
readDirectory(dir, recursive) {
return this.page.cmd("fileList", [
dir, // directory
]).then(res => {
if(recursive) {
return res.sort(); // If recursive, return as given
} else {
return res.map(file => { // Otherwise, crop by "/" symbol
if(file.indexOf("/") == -1) {
return file;
} else {
return file.substr(0, file.indexOf("/"));
}
}).reduce((arr, cur) => { // And make them unique
return arr.indexOf(cur) > -1 ? arr : arr.concat(cur);
}, []).sort();
}
});
}
getType(file) {
if(file == "") {
return Promise.resolve("dir");
}
let dir = file.split("/");
let relative = dir.pop();
dir = dir.join("/");
return this.page.cmd("fileList", [
dir, // directory
]).then(res => {
res = res.map(file => { // Crop by "/" symbol
if(file.indexOf("/") == -1) {
return file;
} else {
return file.substr(0, file.indexOf("/")) + "/";
}
});
if(res.indexOf(relative) > -1) {
return "file";
} else if(res.indexOf(relative + "/") > -1) {
return "dir";
} else {
return Promise.reject("File doesn't exist: " + file);
}
});
}
toBase64(str, bytes) {
return btoa(bytes ? str : unescape(encodeURIComponent(str)));
}
fromBase64(str, bytes) {
return bytes ? atob(str) : decodeURIComponent(escape(atob(str)));
}
}
\ No newline at end of file
const CMD_INNER_READY = 'innerReady'
const CMD_RESPONSE = 'response'
const CMD_WRAPPER_READY = 'wrapperReady'
const CMD_PING = 'ping'
const CMD_PONG = 'pong'
const CMD_WRAPPER_OPENED_WEBSOCKET = 'wrapperOpenedWebsocket'
const CMD_WRAPPER_CLOSE_WEBSOCKET = 'wrapperClosedWebsocket'
class ZeroFrame {
constructor(url) {
this.url = url
this.waiting_cb = {}
this.wrapper_nonce = document.location.href.replace(/.*wrapper_nonce=([A-Za-z0-9]+).*/, "$1")
this.connect()
this.next_message_id = 1
this.init()
}
init() {
return this
}
connect() {
this.target = window.parent
window.addEventListener('message', e => this.onMessage(e), false)
this.cmd(CMD_INNER_READY)
}
onMessage(e) {
let message = e.data
let cmd = message.cmd
if (cmd === CMD_RESPONSE) {
if (this.waiting_cb[message.to] !== undefined) {
this.waiting_cb[message.to](message.result)
}
else {
this.log("Websocket callback not found:", message)
}
} else if (cmd === CMD_WRAPPER_READY) {
this.cmd(CMD_INNER_READY)
} else if (cmd === CMD_PING) {
this.response(message.id, CMD_PONG)
} else if (cmd === CMD_WRAPPER_OPENED_WEBSOCKET) {
this.onOpenWebsocket()
} else if (cmd === CMD_WRAPPER_CLOSE_WEBSOCKET) {
this.onCloseWebsocket()
} else {
this.onRequest(cmd, message)
}
}
onRequest(cmd, message) {
this.log("Unknown request", message)
}
response(to, result) {
this.send({
cmd: CMD_RESPONSE,
to: to,
result: result
})
}
cmd(cmd, params={}, cb=null) {
this.send({
cmd: cmd,
params: params
}, cb)
}
send(message, cb=null) {
message.wrapper_nonce = this.wrapper_nonce
message.id = this.next_message_id
this.next_message_id++
this.target.postMessage(message, '*')
if (cb) {
this.waiting_cb[message.id] = cb
}
}
log(...args) {
console.log.apply(console, ['[ZeroFrame]'].concat(args))
}
onOpenWebsocket() {
this.log('Websocket open')
}
onCloseWebsocket() {
this.log('Websocket close')
}
}
class ZeroPage {
constructor(frame) {
if(typeof frame != "object" || !frame instanceof ZeroFrame) {
throw new Error("frame should be an instance of ZeroFrame");
}
this.frame = frame;
this.progressId = 0;
this.savedPrivateKey = "";
this.initEventListeners();
}
/********************************* Logging ********************************/
logWith(type, args) {
let msg = args.map(v => this.objectToString(v)).join("\n");
this.cmd("wrapperNotification", [type, msg]);
}
log() {
console.info.apply(console, Array.prototype.slice.call(arguments));
this.logWith("info", Array.prototype.slice.call(arguments));
}
warn() {
console.warn.apply(console, Array.prototype.slice.call(arguments));
this.logWith("error", Array.prototype.slice.call(arguments));
}
error() {
console.error.apply(console, Array.prototype.slice.call(arguments));
this.logWith("error", Array.prototype.slice.call(arguments));
}
progress() {
let id = "progress" + (this.progressId++);
let msg;
let percent = 0;
let done = false;
let obj = {
setPercent: p => {
if(done) return;
percent = p;
if(percent == 0) {
this.cmd("wrapperProgress", [
id, // ID
msg, // message
0.05 // percent
]);
this.cmd("wrapperProgress", [
id, // ID
msg, // message
0 // percent
]);
} else {
this.cmd("wrapperProgress", [
id, // ID
msg, // message
percent // percent
]);
}
},
setMessage: (...args) => {
if(done) return;
msg = args.map(v => this.objectToString(v)).join("\n");
this.cmd("wrapperProgress", [
id, // ID
msg, // message
percent // percent
]);
},
done: () => {
if(done) return;
obj.setPercent(100);
done = true;
}
};
obj.setMessage.apply(this, Array.prototype.slice.call(arguments));
return obj;
}
prompt(msg, type) {
msg = this.objectToString(msg);
return this.cmd("wrapperPrompt", [msg, type || "text"]);
}
alert(msg) {
msg = this.objectToString(msg);
this.cmd("wrapperNotification", ["info", msg]);
}
confirm(msg, ok) {
return this.cmd("wrapperConfirm", [msg, ok || "OK"]);
}
/******************************** Commands ********************************/
cmd(cmd, params) {
return new Promise((resolve, reject) => {
this.frame.cmd(cmd, params || [], res => {
if(arguments.length) {
resolve(res);
} else {
resolve();
}
});
});
}
/****************************** EventEmmiter ******************************/
initEventListeners() {
this.eventListeners = {
on: {},
once: {}
};
this.frame.onRequest = (cmd, msg) => {
this.emit(cmd, msg);
};
}
on(cmd, callback) {
if(!this.eventListeners.on.hasOwnProperty(cmd)) {
this.eventListeners.on[cmd] = [];
}
this.eventListeners.on[cmd].push(callback);
}
off(cmd, callback) {
if(this.eventListeners.on.hasOwnProperty(cmd)) {
if(this.eventListeners.on[cmd].indexOf(callback) != -1) {
this.eventListeners.on[cmd].splice(this.eventListeners.on[cmd].indexOf(callback), 1);
}
}
if(this.eventListeners.once.hasOwnProperty(cmd)) {
if(this.eventListeners.once[cmd].indexOf(callback) != -1) {
this.eventListeners.once[cmd].splice(this.eventListeners.once[cmd].indexOf(callback), 1);
}
}
}
once(cmd, callback) {
if(!this.eventListeners.once.hasOwnProperty(cmd)) {
this.eventListeners.once[cmd] = [];
}