refactor: break up ap/index.js
Now it is more obvious that I only handle the homepage from the library and have the login as an implementation detail. Once I figure out how to talk to Vervis' API I can drop Cheerio and use ReST instead. Signed-off-by: André Jaenisch <andre.jaenisch@posteo.de>
This commit is contained in:
parent
eca61c975e
commit
bafd831696
3 changed files with 151 additions and 115 deletions
87
src/lib/server/ap/homepage.js
Normal file
87
src/lib/server/ap/homepage.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import axios, { AxiosHeaders } from 'axios';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
|
|
||||||
import pkg from '../../../../package.json';
|
import pkg from '../../../../package.json';
|
||||||
|
import { getHomepage } from './homepage.js';
|
||||||
|
|
||||||
const loginResponse = {
|
const loginResponse = {
|
||||||
id: '87bcb6de-bb70-11ee-b719-6756da82e80f',
|
id: '87bcb6de-bb70-11ee-b719-6756da82e80f',
|
||||||
|
@ -68,118 +69,3 @@ export const requests = {
|
||||||
return Promise.reject(new Error('Invalid Login'));
|
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;
|
|
||||||
}
|
|
||||||
|
|
63
src/lib/server/ap/login.js
Normal file
63
src/lib/server/ap/login.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue