diff --git a/src/lib/server/ap/homepage.js b/src/lib/server/ap/homepage.js new file mode 100644 index 0000000..75ad395 --- /dev/null +++ b/src/lib/server/ap/homepage.js @@ -0,0 +1,87 @@ +/* Private functions dealing with parsing the homepage of a Vervis instance. + * Copyright (C) 2024 André Jaenisch + * SPDX-FileCopyrightText: 2024 André Jaenisch + * SPDX-License-Identifier: AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License along with this program. If not, see . + */ + +import { AxiosHeaders } from 'axios'; +import * as cheerio from 'cheerio'; + +import { getRemoteLogin, postRemoteLogin } from './login.js'; + +export async function getHomepage({ account, passphrase, server }) { + const vervis = + { + 1: 'https://fig.fr33domlover.site', + 2: 'https://grape.fr33domlover.site', + 3: 'https://walnut.fr33domlover.site' + }[server] || null; + + const loginFormData = await getRemoteLogin(vervis); + const loggedInResponse = await postRemoteLogin({ + username: account, + password: passphrase, + loginFormData + }); + + if (loggedInResponse.status === 200) { + const headers = new AxiosHeaders(); + headers.set({ Cookie: loggedInResponse.headers['set-cookie'].join(';') }); + + const response = await loginFormData.instance.get('/', { + headers + }); + + const patches = []; + const projects = []; + const repos = []; + const teams = []; + const tickets = []; + + const dom = cheerio.load(response.data); + if (dom('h2:contains("Your teams") + p').text().includes("aren't a member")) { + console.log('No teams'); + } + + if (dom('h2:contains("Your repos") + ul').text() === '') { + console.log('No repos'); + } + + if (dom('h2:contains("Your ticket trackers") + ul').text() === '') { + console.log('No ticket trackers'); + } + + if (dom('h2:contains("Your patch trackers") + ul').text() === '') { + console.log('No patch trackers'); + } + + if (dom('h2:contains("Your projects") + ul').text() === '') { + console.log('No projects'); + } else { + dom('h2:contains("Your projects") + ul li a') + .get() + .map((a) => { + projects.push(dom(a).text()); + }); + } + + return { + cookies: response.headers['set-cookie'].join(';'), + patches, + projects, + repos, + teams, + tickets, + username: account, + vervis + }; + } + + return null; +} diff --git a/src/lib/server/ap/index.js b/src/lib/server/ap/index.js index 4ace98a..c454041 100644 --- a/src/lib/server/ap/index.js +++ b/src/lib/server/ap/index.js @@ -16,6 +16,7 @@ import axios, { AxiosHeaders } from 'axios'; import * as cheerio from 'cheerio'; import pkg from '../../../../package.json'; +import { getHomepage } from './homepage.js'; const loginResponse = { id: '87bcb6de-bb70-11ee-b719-6756da82e80f', @@ -68,118 +69,3 @@ export const requests = { return Promise.reject(new Error('Invalid Login')); } }; - -async function getRemoteLogin(vervis) { - const httpsAgent = new Agent({ rejectUnauthorized: false }); - const headers = new AxiosHeaders(); - headers.setUserAgent(`Anvil/${pkg.version}`); - const instance = axios.create({ - baseURL: vervis, - headers, - httpsAgent, - withCredentials: true - }); - const response = await instance.get('/auth/login'); - - const dom = cheerio.load(response.data); - const form = dom('form'); - - return { - instance, - action: form.attr('action'), - csrf: dom('form input[name="_token"]').attr('value'), - enctype: form.attr('enctype'), - method: form.attr('method'), - cookies: response.headers['set-cookie'] - }; -} - -async function postRemoteLogin({ username, password, loginFormData }) { - const headers = new AxiosHeaders(); - headers.setContentType(loginFormData.enctype); - headers.set({ Cookie: loginFormData.cookies.join(';') }); - - const data = { - _token: loginFormData.csrf, - f1: username, - f2: password - }; - - return loginFormData.instance({ - method: loginFormData.method, - url: loginFormData.action, - headers, - data - }); -} - -async function getHomepage({ account, passphrase, server }) { - const vervis = - { - 1: 'https://fig.fr33domlover.site', - 2: 'https://grape.fr33domlover.site', - 3: 'https://walnut.fr33domlover.site' - }[server] || null; - - const loginFormData = await getRemoteLogin(vervis); - const loggedInResponse = await postRemoteLogin({ - username: account, - password: passphrase, - loginFormData - }); - - if (loggedInResponse.status === 200) { - const headers = new AxiosHeaders(); - headers.set({ Cookie: loggedInResponse.headers['set-cookie'].join(';') }); - - const response = await loginFormData.instance.get('/', { - headers - }); - - const patches = []; - const projects = []; - const repos = []; - const teams = []; - const tickets = []; - - const dom = cheerio.load(response.data); - if (dom('h2:contains("Your teams") + p').text().includes("aren't a member")) { - console.log('No teams'); - } - - if (dom('h2:contains("Your repos") + ul').text() === '') { - console.log('No repos'); - } - - if (dom('h2:contains("Your ticket trackers") + ul').text() === '') { - console.log('No ticket trackers'); - } - - if (dom('h2:contains("Your patch trackers") + ul').text() === '') { - console.log('No patch trackers'); - } - - if (dom('h2:contains("Your projects") + ul').text() === '') { - console.log('No projects'); - } else { - dom('h2:contains("Your projects") + ul li a') - .get() - .map((a) => { - projects.push(dom(a).text()); - }); - } - - return { - cookies: response.headers['set-cookie'].join(';'), - patches, - projects, - repos, - teams, - tickets, - username: account, - vervis - }; - } - - return null; -} diff --git a/src/lib/server/ap/login.js b/src/lib/server/ap/login.js new file mode 100644 index 0000000..423c8b9 --- /dev/null +++ b/src/lib/server/ap/login.js @@ -0,0 +1,63 @@ +/* Private functions dealing with the login into a Vervis instance. + * Copyright (C) 2024 André Jaenisch + * SPDX-FileCopyrightText: 2024 André Jaenisch + * SPDX-License-Identifier: AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License along with this program. If not, see . + */ +import { Agent } from 'node:https'; + +import axios, { AxiosHeaders } from 'axios'; +import * as cheerio from 'cheerio'; + +import pkg from '../../../../package.json'; + +export async function getRemoteLogin(vervis) { + const httpsAgent = new Agent({ rejectUnauthorized: false }); + const headers = new AxiosHeaders(); + headers.setUserAgent(`Anvil/${pkg.version}`); + const instance = axios.create({ + baseURL: vervis, + headers, + httpsAgent, + withCredentials: true + }); + const response = await instance.get('/auth/login'); + + const dom = cheerio.load(response.data); + const form = dom('form'); + + return { + instance, + action: form.attr('action'), + csrf: dom('form input[name="_token"]').attr('value'), + enctype: form.attr('enctype'), + method: form.attr('method'), + cookies: response.headers['set-cookie'] + }; +} + +export async function postRemoteLogin({ username, password, loginFormData }) { + const headers = new AxiosHeaders(); + headers.setContentType(loginFormData.enctype); + headers.set({ Cookie: loginFormData.cookies.join(';') }); + + const data = { + _token: loginFormData.csrf, + f1: username, + f2: password + }; + + return loginFormData.instance({ + method: loginFormData.method, + url: loginFormData.action, + headers, + data + }); +} + +