Skip to content
This repository was archived by the owner on May 21, 2022. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
276 changes: 186 additions & 90 deletions bot.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fetch from 'node-fetch';
import getPixels from "get-pixels";
import WebSocket from 'ws';
import https from 'https'

const VERSION_NUMBER = 4;

Expand All @@ -12,19 +13,35 @@ const args = process.argv.slice(2);
// console.error("Missing access token.")
// process.exit(1);
//}
if (args.length != 1 && !process.env.REDDIT_SESSION) {
console.error("Missing reddit_session cookie.")


let redditSessionCookies = (process.env.REDDIT_SESSION || args[0])
if (redditSessionCookies) redditSessionCookies = redditSessionCookies.split(';')

let userNames = (process.env.BOT_USERNAME || false)
if (userNames) userNames = userNames.split(';');
let passWords = (process.env.BOT_PASSWORD || false)
if (passWords) passWords = passWords.split(';');

if (userNames || passWords) {
if (userNames?.length !== passWords?.length) {
console.error('Een user per password graag (en ook andersom).');
userNames = false;
passWords = false;
}
}
if (!(redditSessionCookies || (userNames && passWords))) {
console.error("Missing credintials cookie.")
process.exit(1);
}

let redditSessionCookies = (process.env.REDDIT_SESSION || args[0]).split(';');
if(!redditSessionCookies) redditSessionCookies = [];

var hasTokens = false;

let accessTokens;
let defaultAccessToken;

if (redditSessionCookies.length > 4) {
if (redditSessionCookies?.length > 4) {
console.warn("Meer dan 4 reddit accounts per IP addres wordt niet geadviseerd!")
}

Expand All @@ -33,7 +50,7 @@ var currentOrders;
var currentOrderList;

const COLOR_MAPPINGS = {
'#BE0039': 1,
'#BE0039': 1,
'#FF4500': 2,
'#FFA800': 3,
'#FFD635': 4,
Expand Down Expand Up @@ -64,8 +81,8 @@ let rgbaJoin = (a1, a2, rowSize = 1000, cellSize = 4) => {
const rows = a1.length / rawRowSize;
let result = new Uint8Array(a1.length + a2.length);
for (var row = 0; row < rows; row++) {
result.set(a1.slice(rawRowSize * row, rawRowSize * (row+1)), rawRowSize * 2 * row);
result.set(a2.slice(rawRowSize * row, rawRowSize * (row+1)), rawRowSize * (2 * row + 1));
result.set(a1.slice(rawRowSize * row, rawRowSize * (row + 1)), rawRowSize * 2 * row);
result.set(a2.slice(rawRowSize * row, rawRowSize * (row + 1)), rawRowSize * (2 * row + 1));
}
return result;
};
Expand All @@ -91,7 +108,7 @@ let getPendingWork = (work, rgbaOrder, rgbaCanvas) => {
};

(async function () {
refreshTokens();
await refreshTokens(); // wachten totdat je de tokens hebt (duurt nu langer);
connectSocket();

startPlacement();
Expand Down Expand Up @@ -119,8 +136,87 @@ function startPlacement() {
}
}


function request(options, body) {
let promise = new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
resolve(res);
});

req.on('error', (e) => {
reject(error);
});
if (body) {
req.write(body); //stuurd de pass en username
}
req.end();
});
return promise
}
async function GetToken(username, password) {
let place_url = "https://www.reddit.com/r/place/"
let reddit_url = "https://www.reddit.com/login/"
let response = await fetch(reddit_url); //pak de csrf token van de login form (ook nodig voor sesion cookie)
let responseText = await response.text();

let csrf = responseText.match(/csrf_token" value\="(.*?)">/)[1]; // crsf token

let cookies = response.headers.raw()['set-cookie']; //alle cookie
let session = cookies[0].match(/session\=(.*?;)/)[1]; // eerste is altijd (hoop ik) de session cookie

let body = `csrf_token=${csrf}&password=${password}&username=${username}`; //body van login request

const options = {
hostname: 'www.reddit.com',
port: 443,
path: '/login',
method: 'POST',
headers: {
'cookie': `session=${session}`, //login request heeft session cookie nodig (van de eerde login form)
}
};

//node fetch werkt hier niet want die set bepalde header die niet mogen geset worden
let result = await request(options, body);
let cookie_reddit_session;
try {
cookie_reddit_session = result.headers['set-cookie'][0].match(/reddit_session\=(.*?);/)[1]; //reddit_session cookie
} catch (error) {
console.error(error);
}

response = await fetch(place_url, {
headers: {
cookie: `reddit_session=${cookie_reddit_session}`
}
})
responseText = await response.text();

return responseText.split('\"accessToken\":\"')[1].split('"')[0];
}


async function refreshTokens() {
let tokens = [];
if (userNames && passWords) {
for (let i = 0; i < userNames.length; i++) {
let password = passWords[i];
let username = userNames[i];
console.log(`Reddit session token ophalen voor ${username}`);
let token = await GetToken(username, password);
tokens.push(token);
}
console.log("Refreshed tokens: ", tokens)

accessTokens = tokens;
defaultAccessToken = tokens[0];
hasTokens = true;
return
}




for (const cookie of redditSessionCookies) {
const response = await fetch("https://www.reddit.com/r/place/", {
headers: {
Expand All @@ -145,7 +241,7 @@ function connectSocket() {

socket = new WebSocket('wss://placenl.noahvdaa.me/api/ws');

socket.onerror = function(e) {
socket.onerror = function (e) {
console.error("Socket error: " + e.message)
}

Expand Down Expand Up @@ -188,7 +284,7 @@ async function attemptPlace(accessToken) {
setTimeout(retry, 2000); // probeer opnieuw in 2sec.
return;
}

var map0;
var map1;
try {
Expand Down Expand Up @@ -225,13 +321,13 @@ async function attemptPlace(accessToken) {
try {
if (data.errors) {
const error = data.errors[0];
if (error.extensions && error.extensions.nextAvailablePixelTimestamp) {
const nextPixel = error.extensions.nextAvailablePixelTs + 3000;
if (error.extensions && error.extensions.nextAvailablePixelTimestamp || error.extensions.nextAvailablePixelTs) {
const nextPixel = ( error.extensions.nextAvailablePixelTimestamp || error.extensions.nextAvailablePixelTs) + 3000;
const nextPixelDate = new Date(nextPixel);
const delay = nextPixelDate.getTime() - Date.now();
console.log(`Pixel te snel geplaatst! Volgende pixel wordt geplaatst om ${nextPixelDate.toLocaleTimeString()}.`)
setTimeout(retry, delay);
} else {
}else {
console.error(`[!!] Kritieke fout: ${error.message}. Heb je de 'reddit_session' cookie goed gekopieerd?`);
console.error(`[!!] Los dit op en herstart het script`);
}
Expand All @@ -250,96 +346,96 @@ async function attemptPlace(accessToken) {

function place(x, y, color, accessToken = defaultAccessToken) {
socket.send(JSON.stringify({ type: 'placepixel', x, y, color }));
return fetch('https://gql-realtime-2.reddit.com/query', {
method: 'POST',
body: JSON.stringify({
'operationName': 'setPixel',
'variables': {
'input': {
'actionName': 'r/replace:set_pixel',
'PixelMessageData': {
'coordinate': {
'x': x % 1000,
'y': y % 1000
},
'colorIndex': color,
'canvasIndex': (x > 999 ? 1 : 0)
}
}
},
'query': 'mutation setPixel($input: ActInput!) {\n act(input: $input) {\n data {\n ... on BasicMessage {\n id\n data {\n ... on GetUserCooldownResponseMessageData {\n nextAvailablePixelTimestamp\n __typename\n }\n ... on SetPixelResponseMessageData {\n timestamp\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n'
}),
headers: {
'origin': 'https://hot-potato.reddit.com',
'referer': 'https://hot-potato.reddit.com/',
'apollographql-client-name': 'mona-lisa',
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
});
return fetch('https://gql-realtime-2.reddit.com/query', {
method: 'POST',
body: JSON.stringify({
'operationName': 'setPixel',
'variables': {
'input': {
'actionName': 'r/replace:set_pixel',
'PixelMessageData': {
'coordinate': {
'x': x % 1000,
'y': y % 1000
},
'colorIndex': color,
'canvasIndex': (x > 999 ? 1 : 0)
}
}
},
'query': 'mutation setPixel($input: ActInput!) {\n act(input: $input) {\n data {\n ... on BasicMessage {\n id\n data {\n ... on GetUserCooldownResponseMessageData {\n nextAvailablePixelTimestamp\n __typename\n }\n ... on SetPixelResponseMessageData {\n timestamp\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n'
}),
headers: {
'origin': 'https://hot-potato.reddit.com',
'referer': 'https://hot-potato.reddit.com/',
'apollographql-client-name': 'mona-lisa',
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
});
}

async function getCurrentImageUrl(id = '0') {
return new Promise((resolve, reject) => {
const ws = new WebSocket('wss://gql-realtime-2.reddit.com/query', 'graphql-ws', {
headers : {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:98.0) Gecko/20100101 Firefox/98.0",
"Origin": "https://hot-potato.reddit.com"
}
});

ws.onopen = () => {
ws.send(JSON.stringify({
'type': 'connection_init',
'payload': {
'Authorization': `Bearer ${defaultAccessToken}`
}
}));

ws.send(JSON.stringify({
'id': '1',
'type': 'start',
'payload': {
'variables': {
'input': {
'channel': {
'teamOwner': 'AFD2022',
'category': 'CANVAS',
'tag': id
}
}
},
'extensions': {},
'operationName': 'replace',
'query': 'subscription replace($input: SubscribeInput!) {\n subscribe(input: $input) {\n id\n ... on BasicMessage {\n data {\n __typename\n ... on FullFrameMessageData {\n __typename\n name\n timestamp\n }\n }\n __typename\n }\n __typename\n }\n}'
}
}));
};

ws.onmessage = (message) => {
const { data } = message;
const parsed = JSON.parse(data);
return new Promise((resolve, reject) => {
const ws = new WebSocket('wss://gql-realtime-2.reddit.com/query', 'graphql-ws', {
headers: {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:98.0) Gecko/20100101 Firefox/98.0",
"Origin": "https://hot-potato.reddit.com"
}
});

ws.onopen = () => {
ws.send(JSON.stringify({
'type': 'connection_init',
'payload': {
'Authorization': `Bearer ${defaultAccessToken}`
}
}));

ws.send(JSON.stringify({
'id': '1',
'type': 'start',
'payload': {
'variables': {
'input': {
'channel': {
'teamOwner': 'AFD2022',
'category': 'CANVAS',
'tag': id
}
}
},
'extensions': {},
'operationName': 'replace',
'query': 'subscription replace($input: SubscribeInput!) {\n subscribe(input: $input) {\n id\n ... on BasicMessage {\n data {\n __typename\n ... on FullFrameMessageData {\n __typename\n name\n timestamp\n }\n }\n __typename\n }\n __typename\n }\n}'
}
}));
};

ws.onmessage = (message) => {
const { data } = message;
const parsed = JSON.parse(data);

if (parsed.type === 'connection_error') {
console.error(`[!!] Kon /r/place map niet laden: ${parsed.payload.message}. Is de access token niet meer geldig?`);
}

// TODO: ew
if (!parsed.payload || !parsed.payload.data || !parsed.payload.data.subscribe || !parsed.payload.data.subscribe.data) return;
// TODO: ew
if (!parsed.payload || !parsed.payload.data || !parsed.payload.data.subscribe || !parsed.payload.data.subscribe.data) return;

ws.close();
resolve(parsed.payload.data.subscribe.data.name + `?noCache=${Date.now() * Math.random()}`);
}
ws.close();
resolve(parsed.payload.data.subscribe.data.name + `?noCache=${Date.now() * Math.random()}`);
}


ws.onerror = reject;
});
ws.onerror = reject;
});
}

function getMapFromUrl(url) {
return new Promise((resolve, reject) => {
getPixels(url, function(err, pixels) {
if(err) {
getPixels(url, function (err, pixels) {
if (err) {
console.log("Bad image path")
reject()
return
Expand All @@ -350,7 +446,7 @@ function getMapFromUrl(url) {
}

function rgbToHex(r, g, b) {
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
}

let rgbaOrderToHex = (i, rgbaOrder) =>
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.