summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/constants.js12
-rw-r--r--src/main.js8
-rw-r--r--src/session.js124
3 files changed, 144 insertions, 0 deletions
diff --git a/src/constants.js b/src/constants.js
new file mode 100644
index 0000000..5087f3f
--- /dev/null
+++ b/src/constants.js
@@ -0,0 +1,12 @@
+export const AGGIETIME_URI = "https://aggietimeultra.usu.edu";
+export const LOGIN_PATH = "api/v1/auth/login";
+export const EXECUTION_SELECTOR = "input[type=hidden][name=execution]";
+export const DUO_IFRAME_SELECTOR = "#duo_iframe";
+export const DUO_FACTOR = "Duo Push";
+export const DUO_INPUT_FIELD_SELECTORS = [
+ "input[type=hidden][name=sid]",
+ "input[type=hidden][name=out_of_date]",
+ "input[type=hidden][name=days_out_of_date]",
+ "input[type=hidden][name=days_to_block]",
+ "input[type=hidden][name=preferred_device]",
+];
diff --git a/src/main.js b/src/main.js
new file mode 100644
index 0000000..80243cd
--- /dev/null
+++ b/src/main.js
@@ -0,0 +1,8 @@
+import { login } from "./session.js";
+import * as dotenv from "dotenv";
+
+dotenv.config();
+
+(async () => {
+ await login(process.env.A_NUMBER, process.env.PASSWORD);
+})();
diff --git a/src/session.js b/src/session.js
new file mode 100644
index 0000000..ae6d593
--- /dev/null
+++ b/src/session.js
@@ -0,0 +1,124 @@
+import {
+ AGGIETIME_URI,
+ LOGIN_PATH,
+ DUO_IFRAME_SELECTOR,
+ DUO_FACTOR,
+ DUO_INPUT_FIELD_SELECTORS,
+ EXECUTION_SELECTOR,
+} from "./constants.js";
+
+import { parse } from "node-html-parser";
+import axios from "axios";
+
+const make_auth_params = (username, password, execution) =>
+ new URLSearchParams({
+ username,
+ password,
+ execution,
+ _eventId: "submit",
+ geolocation: "",
+ });
+
+const push_duo_get_cookie = async (
+ duo_iframe_obj,
+ response_url,
+ username,
+ password,
+ execution
+) => {
+ const [duo_host, duo_sig, duo_src] = [
+ "data-host",
+ "data-sig-request",
+ "src",
+ ].map((attr) => duo_iframe_obj.getAttribute(attr));
+ const transaction_id = duo_sig.split(":")[0];
+
+ const duo = axios.create({
+ withCredentials: true,
+ baseURL: `https://${duo_host}`,
+ });
+
+ const duo_frame = await duo
+ .post(
+ `/frame/web/v1/auth?tx=${transaction_id}&parent=${response_url}&v=2.6`
+ )
+ .then(({ data }) => parse(data));
+
+ const [sid, out_of_date, days_out_of_date, days_to_block, device] =
+ DUO_INPUT_FIELD_SELECTORS.map((selector) =>
+ duo_frame.querySelector(selector).getAttribute("value")
+ );
+
+ const push_params = new URLSearchParams({
+ sid,
+ out_of_date,
+ days_out_of_date,
+ days_to_block,
+ device,
+ factor: DUO_FACTOR,
+ });
+
+ const {
+ response: { txid },
+ } = await duo.post("/frame/prompt", push_params).then(({ data }) => data);
+
+ return await wait_approve_duo(duo, sid, txid);
+};
+
+const wait_approve_duo = async (duo, sid, txid) => {
+ // First status to confirm device was pushed to
+ // Second to long-poll for approval :3
+ const status_params = new URLSearchParams({
+ sid,
+ txid,
+ });
+
+ const data = await duo
+ .post("/frame/status", status_params)
+ .then(async ({ data }) => {
+ if (data.stat === "OK" && data.response.status_code === "pushed")
+ return await duo
+ .post("/frame/status", status_params)
+ .then(({ data }) => data);
+ return data;
+ });
+
+ const {
+ response: { result_url },
+ } = data;
+
+ console.log(data);
+
+ return await duo.post(result_url, new URLSearchParams({ sid }));
+};
+
+export const login = async (username, password) => {
+ const login_page_promise = axios.get(`${AGGIETIME_URI}/${LOGIN_PATH}`);
+
+ const {
+ request: {
+ res: { responseUrl: response_url },
+ },
+ } = await login_page_promise;
+ const cas_root = await login_page_promise.then(({ data }) => parse(data));
+ const execution = cas_root
+ .querySelector(EXECUTION_SELECTOR)
+ .getAttribute("value");
+
+ const duo_iframe_obj = await axios
+ .post(response_url, make_auth_params(username, password, execution))
+ .then(({ data }) => parse(data).querySelector(DUO_IFRAME_SELECTOR));
+
+ const cookie = await push_duo_get_cookie(
+ duo_iframe_obj,
+ response_url,
+ username,
+ password,
+ execution
+ );
+
+ console.log(cookie);
+ console.log(cookie.data);
+
+ return cookie;
+};