123 lines
3 KiB
JavaScript
123 lines
3 KiB
JavaScript
const EventEmitter = require("events");
|
|
|
|
module.exports.XSSBook = class XSSBook extends EventEmitter {
|
|
constructor({ url, bridge_username, room }) {
|
|
super();
|
|
|
|
this.url = url;
|
|
this.bridge_username = bridge_username;
|
|
this.room = room;
|
|
|
|
this.tokens = {};
|
|
this.posts = {};
|
|
|
|
this.pollLoop();
|
|
}
|
|
|
|
async api(url, method, data, token) {
|
|
return await fetch(this.url + url, {
|
|
method,
|
|
headers: {
|
|
"Cookie": token ? "auth=" + encodeURIComponent(token) : undefined,
|
|
"Content-Type": data ? "application/json" : undefined,
|
|
},
|
|
body: data ? JSON.stringify(data) : undefined,
|
|
});
|
|
}
|
|
|
|
async getUserToken(username) {
|
|
if(username in this.tokens) {
|
|
return this.tokens[username];
|
|
}
|
|
|
|
let req = await this.api("/api/auth/register", "POST", {
|
|
firstname: username,
|
|
lastname: username === this.bridge_username ? "[bridge]" : "[matrix]",
|
|
email: username,
|
|
password: username,
|
|
gender: username === this.bridge_username ? "matrix bridge" : "matrix user",
|
|
day: 1,
|
|
month: 1,
|
|
year: 1970,
|
|
});
|
|
if(req.ok) {
|
|
const token = decodeURIComponent(/auth=([^;]+);/.exec(req.headers.get("set-cookie"))[1]);
|
|
return this.tokens[username] = token;
|
|
}
|
|
|
|
console.log("couldn't register " + username + ":", await req.text());
|
|
|
|
req = await this.api("/api/auth/login", "POST", {
|
|
email: username,
|
|
password: username,
|
|
});
|
|
if(req.ok) {
|
|
const token = decodeURIComponent(/auth=([^;]+);/.exec(req.headers.get("set-cookie"))[1]);
|
|
return this.tokens[username] = token;
|
|
}
|
|
|
|
console.log("couldn't login " + username + ":", await req.text());
|
|
|
|
throw new Error("Couldn't get token for " + username);
|
|
}
|
|
|
|
async apiUser(url, method, data, username) {
|
|
const token = await this.getUserToken(username);
|
|
return await this.api(url, method, data, token);
|
|
}
|
|
|
|
async getUsers(ids) {
|
|
const req = await this.apiUser("/api/users/load", "POST", {
|
|
ids,
|
|
}, this.bridge_username);
|
|
|
|
return await req.json();
|
|
}
|
|
|
|
async post(username, content) {
|
|
const res = await this.apiUser("/api/posts/create", "POST", {
|
|
content,
|
|
}, username);
|
|
return (await res.json()).post_id;
|
|
}
|
|
|
|
async pollLoop() {
|
|
let latest_post_id = 0, first = true;
|
|
while(true) {
|
|
await new Promise(r => setTimeout(r, 5000));
|
|
const req = await this.apiUser("/api/posts/page", "POST", {
|
|
page: 0,
|
|
}, this.bridge_username);
|
|
const posts = await req.json();
|
|
|
|
if(!Array.isArray(posts) || !posts.length) {
|
|
continue;
|
|
}
|
|
|
|
const new_posts = posts.filter(n => n.post_id > latest_post_id);
|
|
if(!new_posts.length) {
|
|
continue;
|
|
}
|
|
|
|
latest_post_id = Math.max(latest_post_id, ...new_posts.map(n => n.post_id));
|
|
|
|
if(first) { // ignore posts from the first sync
|
|
first = false;
|
|
continue;
|
|
}
|
|
|
|
const users_list = await this.getUsers(new_posts.map(n => n.user_id));
|
|
const users = {};
|
|
users_list.forEach(user => {
|
|
users[user.user_id] = user;
|
|
});
|
|
|
|
new_posts.forEach(post => {
|
|
const user = users[post.user_id];
|
|
|
|
this.emit("post", post, user);
|
|
});
|
|
}
|
|
}
|
|
}
|