From 263f3093a805875c6a507e4b17fe173ca3604db5 Mon Sep 17 00:00:00 2001 From: Selcuk Kekec Date: Sat, 13 Aug 2022 01:40:39 +0200 Subject: [PATCH] feat(login-redirect): automatically react on redirect during login procedure (fixes #7) --- package.json | 1 + src/client.test.ts | 14 ++++++++ src/client.ts | 74 ++++++++++++++++++++++++++---------------- src/types/countries.ts | 26 +++++++++++++++ src/types/login.ts | 13 +++++++- 5 files changed, 99 insertions(+), 29 deletions(-) create mode 100644 src/client.test.ts create mode 100644 src/types/countries.ts diff --git a/package.json b/package.json index f071702..df7f365 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "build:types": "tsc --emitDeclarationOnly", "build:js": "babel src --out-dir lib --extensions \".ts,.tsx\" --source-maps inline", "start": "babel-watch --extensions \".ts\" src/index.ts", + "test": "babel-watch --extensions \".ts\" src/client.test.ts", "debug": "babel-watch --inspect 0.0.0.0:9229 --extensions \".ts\" src/index.ts", "lint": "eslint --fix --ext .ts ./src", "format": "prettier --ignore-path .gitignore --write \"src/**/*.+(ts|json)\"", diff --git a/src/client.test.ts b/src/client.test.ts new file mode 100644 index 0000000..d944a2c --- /dev/null +++ b/src/client.test.ts @@ -0,0 +1,14 @@ +import { LibreLinkUpClient } from './client'; + +(async function() { + const username = 'USERNAME'; + const password = 'PASSWORD'; + const libreClient = LibreLinkUpClient({ + username, + password, + connectionIdentifier: 'IDENTIFIER' + }); + + const data = await libreClient.read(); + console.log(data); +})(); diff --git a/src/client.ts b/src/client.ts index 515b24b..604a2a4 100644 --- a/src/client.ts +++ b/src/client.ts @@ -2,11 +2,12 @@ import axios from 'axios'; import { LibreCgmData } from './types/client'; import { ActiveSensor, Connection, GlucoseItem } from './types/connection'; import { ConnectionsResponse, Datum } from './types/connections'; +import { CountryResponse, AE, RegionalMap } from './types/countries'; import { GraphData } from './types/graph'; -import { LoginResponse } from './types/login'; +import { LoginResponse, LoginRedirectResponse } from './types/login'; import { mapData, trendMap } from './utils'; -const LIBRE_LINK_SERVER = 'https://api.libreview.io'; +const LIBRE_LINK_SERVER = 'https://api-us.libreview.io'; type ClientArgs = { username: string; @@ -28,6 +29,7 @@ type ReadResponse = { const urlMap = { login: '/llu/auth/login', connections: '/llu/connections', + countries: '/llu/config/country?country=DE', }; export const LibreLinkUpClient = ({ @@ -62,27 +64,43 @@ export const LibreLinkUpClient = ({ { synchronous: true } ); - const login = async () => { - const loginResponse = await instance.post(urlMap.login, { + const login = async (): Promise => { + const loginResponse = await instance.post(urlMap.login, { email: username, password, }); - jwtToken = loginResponse.data.data.authTicket.token; - return loginResponse; + if ((loginResponse.data as LoginRedirectResponse).data.redirect) { + const redirectResponse = loginResponse.data as LoginRedirectResponse; + const countryNodes = await instance.get(urlMap.countries); + const targetRegion = redirectResponse.data.region as keyof RegionalMap; + const regionDefinition: AE | undefined = countryNodes.data.data.regionalMap[targetRegion]; + + if (!regionDefinition) { + throw new Error( + `Unable to find region '${redirectResponse.data.region}'. + Available nodes are ${Object.keys(countryNodes.data.data.regionalMap).join(', ')}.`); + } + + instance.defaults.baseURL = regionDefinition.lslApi; + return login(); + } + jwtToken = (loginResponse.data as LoginResponse).data.authTicket.token; + + return loginResponse.data as LoginResponse; }; const loginWrapper = (func: () => Promise) => - async (): Promise => { - try { - if (!jwtToken) await login(); - return func(); - } catch (e) { - await login(); - return func(); - } - }; + async (): Promise => { + try { + if (!jwtToken) await login(); + return func(); + } catch (e) { + await login(); + return func(); + } + }; const getConnections = loginWrapper(async () => { const response = await instance.get( @@ -171,19 +189,19 @@ export const LibreLinkUpClient = ({ ); const averageTrend = trendMap[ - parseInt( - ( - Math.round( - (memValues.reduce( - (acc, cur) => acc + trendMap.indexOf(cur.trend), - 0 - ) / - amount) * - 100 - ) / 100 - ).toFixed(0), - 10 - ) + parseInt( + ( + Math.round( + (memValues.reduce( + (acc, cur) => acc + trendMap.indexOf(cur.trend), + 0 + ) / + amount) * + 100 + ) / 100 + ).toFixed(0), + 10 + ) ]; mem = new Map(); diff --git a/src/types/countries.ts b/src/types/countries.ts new file mode 100644 index 0000000..acee674 --- /dev/null +++ b/src/types/countries.ts @@ -0,0 +1,26 @@ +export interface AE { + lslApi: string; + socketHub: string; +} + +export interface RegionalMap { + us: AE; + eu: AE; + fr: AE; + jp: AE; + de: AE; + ap: AE; + au: AE; + ae: AE; +} + +interface Data { + regionalMap: RegionalMap; +} + +export interface CountryResponse { + status: number; + data: Data; +} + + diff --git a/src/types/login.ts b/src/types/login.ts index 212d4ee..3d4d7f8 100644 --- a/src/types/login.ts +++ b/src/types/login.ts @@ -5,6 +5,17 @@ export type LoginArgs = { password: string; }; +export interface LoginRedirectResponse { + status: number; + data: LoginRedirectData; +} + +interface LoginRedirectData { + redirect: boolean; + region: string; +} + + export interface LoginResponse { status: number; data: Data; @@ -66,7 +77,7 @@ interface Llu { } // eslint-disable-next-line @typescript-eslint/no-empty-interface -interface Details {} +interface Details { } interface System { messages: SystemMessages;