1
0
mirror of https://github.com/snobu/destreamer.git synced 2026-01-17 21:42:16 +00:00
Files
destreamer-mirror/src/LoginModules.ts
2021-10-14 20:44:04 +02:00

174 lines
6.0 KiB
TypeScript

import { logger } from './Logger';
import puppeteer from 'puppeteer';
import { getPuppeteerChromiumPath } from './PuppeteerHelper';
import { chromeCacheFolder } from './destreamer';
import { argv } from './CommandLineParser';
import { ShareSession, StreamSession } from './Types';
import { ERROR_CODE } from './Errors';
import { TokenCache } from './TokenCache';
export async function doStreamLogin(url: string, tokenCache: TokenCache, username?: string): Promise<StreamSession> {
logger.info('Launching headless Chrome to perform the OpenID Connect dance...');
const browser: puppeteer.Browser = await puppeteer.launch({
executablePath: getPuppeteerChromiumPath(),
headless: false,
userDataDir: (argv.keepLoginCookies) ? chromeCacheFolder : undefined,
defaultViewport: null,
args: [
'--disable-dev-shm-usage',
'--fast-start',
'--no-sandbox'
]
});
// try-finally because we were leaving zombie processes if there was an error
try {
const page: puppeteer.Page = (await browser.pages())[0];
logger.info('Navigating to login page...');
await page.goto(url, { waitUntil: 'load' });
try {
if (username) {
await page.waitForSelector('input[type="email"]', { timeout: 3000 });
await page.keyboard.type(username);
await page.click('input[type="submit"]');
}
else {
/* If a username was not provided we let the user take actions that
lead up to the video page. */
}
}
catch (e) {
/* If there is no email input selector we aren't in the login module,
we are probably using the cache to aid the login.
It could finish the login on its own if the user said 'yes' when asked to
remember the credentials or it could still prompt the user for a password */
}
await browser.waitForTarget((target: puppeteer.Target) => target.url().endsWith('microsoftstream.com/'), { timeout: 150000 });
logger.info('We are logged in.');
let session: StreamSession | null = null;
let tries = 1;
while (!session) {
try {
let sessionInfo: any;
session = await page.evaluate(
() => {
return {
AccessToken: sessionInfo.AccessToken,
ApiGatewayUri: sessionInfo.ApiGatewayUri,
ApiGatewayVersion: sessionInfo.ApiGatewayVersion
};
}
);
}
catch (error) {
if (tries > 5) {
process.exit(ERROR_CODE.NO_SESSION_INFO);
}
session = null;
tries++;
await page.waitForTimeout(3000);
}
}
tokenCache.Write(session);
logger.info('Wrote access token to token cache.');
logger.info("At this point Chromium's job is done, shutting it down...\n");
return session;
}
finally {
await browser.close();
}
}
export async function doShareLogin(url: string, username?: string): Promise<ShareSession> {
logger.info('Launching headless Chrome to perform the OpenID Connect dance...');
const hostname = new URL(url).hostname;
const browser: puppeteer.Browser = await puppeteer.launch({
executablePath: getPuppeteerChromiumPath(),
headless: false,
devtools: argv.verbose,
userDataDir: (argv.keepLoginCookies) ? chromeCacheFolder : undefined,
defaultViewport: null,
args: [
'--disable-dev-shm-usage',
'--fast-start',
'--no-sandbox'
]
});
// try-finally because we were leaving zombie processes if there was an error
try {
const page: puppeteer.Page = (await browser.pages())[0];
logger.info('Navigating to login page...');
await page.goto(url, { waitUntil: 'load' });
try {
if (username) {
await page.waitForSelector('input[type="email"]', { timeout: 3000 });
await page.keyboard.type(username);
await page.click('input[type="submit"]');
}
else {
/* If a username was not provided we let the user take actions that
lead up to the video page. */
}
}
catch (e) {
/* If there is no email input selector we aren't in the login module,
we are probably using the cache to aid the login.
It could finish the login on its own if the user said 'yes' when asked to
remember the credentials or it could still prompt the user for a password */
}
logger.info('Waiting for target!');
await browser.waitForTarget((target: puppeteer.Target) => target.url().includes(hostname), { timeout: 150000 });
logger.info('We are logged in.');
let session: ShareSession | null = null;
let tries = 1;
while (!session) {
const cookieJar = (await page.cookies()).filter(
biscuit => biscuit.name == 'rtFa' || biscuit.name == 'FedAuth'
);
if (cookieJar.length != 2) {
if (tries > 5) {
process.exit(ERROR_CODE.NO_SESSION_INFO);
}
await page.waitForTimeout(1000 * tries++);
continue;
}
session = {
rtFa: cookieJar.find(biscuit => biscuit.name == 'rtFa')!.value,
FedAuth: cookieJar.find(biscuit => biscuit.name == 'FedAuth')!.value
};
}
logger.info("At this point Chromium's job is done, shutting it down...\n");
// await page.waitForTimeout(1000 * 60 * 60 * 60);
return session;
}
finally {
await browser.close();
}
}