Skip to content
This repository has been archived by the owner on Jan 24, 2023. It is now read-only.

Mysky autologin stored settings and logout #188

Merged
merged 36 commits into from
Feb 15, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7d2fe37
Implement logout and setup auto re-login
mrcnski Dec 9, 2021
6a03865
Fix up loose ends for logout and auto re-login
mrcnski Dec 9, 2021
3ef9ad7
Polyfill Promise.any for Opera
mrcnski Dec 15, 2021
5e60df4
Implement getting preferred portal and redirect flow
mrcnski Dec 15, 2021
6d10fe5
Implement preferred portal flow, move portal login to Main MySky
mrcnski Dec 22, 2021
a56b4fe
Fix a couple of lint warnings
mrcnski Dec 22, 2021
3db1e6a
Merge branch 'main' into mysky-autologin-stored-settings-and-logout
mrcnski Dec 22, 2021
c1a7812
Signal to MySky UI that we are done logging in
mrcnski Jan 7, 2022
a8e518d
Refactor MySky get/setJSON based on GSJ rework
mrcnski Jan 7, 2022
181fd70
Address lint errors
mrcnski Jan 7, 2022
eae675b
Fix compilation issues
mrcnski Jan 12, 2022
10a9209
Update tests to use siasky.net, remove references to SKYNET-TOKEN
mrcnski Jan 12, 2022
3d3ce52
Address review comments
mrcnski Jan 13, 2022
cce3dbb
Merge branch 'main' into mysky-autologin-stored-settings-and-logout
mrcnski Jan 13, 2022
6a19718
Fix build errors
mrcnski Jan 14, 2022
bc5065a
Add some fixes, debug lines, and refactors
mrcnski Jan 17, 2022
d922f2d
Fix some bugs, add debug lines, send URL parameters to UI screens
mrcnski Jan 18, 2022
1815b87
Fix some bugs
mrcnski Jan 20, 2022
ccbf35f
Refactor, get user settings in scripts/ui.ts
mrcnski Jan 20, 2022
4034089
Expose functions to allow skynet-js to auto-relogin
mrcnski Jan 21, 2022
a45f435
Fix domain extraction bugs (also fixing user settings bug)
mrcnski Jan 28, 2022
50be38e
Fix bug in `getJSONEncryptedInternal`
mrcnski Jan 31, 2022
4e10f5c
Fix referrer bug
mrcnski Feb 1, 2022
fe13a7b
Fix integration tests
mrcnski Feb 2, 2022
d5b79d1
Don't make MySky initialization fail if the email is invalid
mrcnski Feb 2, 2022
1b44334
Couple of critical fixes
mrcnski Feb 4, 2022
21a0e4b
Merge branch 'main' into mysky-autologin-stored-settings-and-logout
mrcnski Feb 4, 2022
61602fb
Merge branch 'main' into mysky-autologin-stored-settings-and-logout
ro-tex Feb 7, 2022
49eebcc
Fix unexpected request with seed
mrcnski Feb 7, 2022
5b2f738
Merge remote-tracking branch 'origin/mysky-autologin-stored-settings-…
mrcnski Feb 7, 2022
7a76de1
Merge branch 'main' into mysky-autologin-stored-settings-and-logout
mrcnski Feb 8, 2022
307b83a
Fix lint warnings
mrcnski Feb 8, 2022
58d6196
Address most review comments
mrcnski Feb 11, 2022
f9d0b59
Comment `resolveOnMySkyPortalLogin` and unregister event listener
mrcnski Feb 11, 2022
f441ee5
Add explanatory comments
mrcnski Feb 14, 2022
c951e5c
Merge branch 'main' into mysky-autologin-stored-settings-and-logout
ro-tex Feb 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"testEnvironment": "jsdom"
},
"dependencies": {
"axios": "^0.24.0",
"buffer": "^6.0.3",
"confusables": "^1.0.0",
"crypto-browserify": "^3.12.0",
Expand Down Expand Up @@ -72,6 +73,7 @@
"@typescript-eslint/eslint-plugin": "^5.7.0",
"@typescript-eslint/parser": "^5.7.0",
"autoprefixer": "^10.4.0",
"core-js": "^3.20.0",
"eslint": "^8.5.0",
"eslint-plugin-jsdoc": "^37.4.0",
"husky": "^7.0.4",
Expand Down
88 changes: 31 additions & 57 deletions scripts/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import {
import { MySky, SkynetClient } from "skynet-js";

import { hashWithSalt } from "../src/crypto";
import { login, register } from "../src/portal-account";
import { checkStoredSeed, EMAIL_STORAGE_KEY, SEED_STORAGE_KEY } from "../src/mysky";
import { checkStoredSeed, EMAIL_STORAGE_KEY, PORTAL_LOGIN_COMPLETE_SENTINEL_KEY, SEED_STORAGE_KEY } from "../src/mysky";
import {
getPermissionsProviderUrl,
relativePermissionsDisplayUrl,
Expand All @@ -32,6 +31,9 @@ let parentConnection: Connection | null = null;

// Set value of dev on load.
let dev = false;
/// #if ENV == 'dev'
dev = true;
/// #endif

// ======
// Events
Expand Down Expand Up @@ -65,10 +67,6 @@ window.onerror = function (error: any) {
// TODO: Wrap in a try-catch block? Does onerror handler catch thrown errors?
// Code that runs on page load.
window.onload = () => {
/// #if ENV == 'dev'
dev = true;
/// #endif

void init();
};

Expand Down Expand Up @@ -117,6 +115,9 @@ async function requestLoginAccess(permissions: Permission[]): Promise<[boolean,
// Save the seed and email in local storage.
saveSeedAndEmail(seed, email);

// Wait for Main MySky to login successfully.
await waitForMySkyPortalLogin();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit looks kind of weird to be naming an async function waitFor because you don't necessarily await it


// Pass in any request permissions and get a permissions response.
const permissionsResponse = await getPermissions(seed, permissions);

Expand Down Expand Up @@ -156,12 +157,7 @@ async function checkBrowserSupported(): Promise<void> {
* then we display the signin-connect page where the user may connect his email
* on signin.
*
* 5. If we got the email, then we register/login to set the JWT cookie.
*
* 6. If the user provided a new email at some point, then we save it in user
* settings, after having successfully connected to a portal account.
*
* (7. We return the seed and email and save them in storage in another
* (5. We return the seed and email and save them in storage in another
* function, which triggers Main MySky's storage listener.)
*
* @returns - The seed and email.
Expand Down Expand Up @@ -208,16 +204,6 @@ async function getSeedAndEmail(): Promise<[Uint8Array, string | null]> {
}
}

// Register/login.
if (email) {
await connectToPortalAccount(seed, email);
}

// TODO: Save the new provided email in user settings.
if (emailProvidedByUser) {
await saveEmailInSettings();
}

return [seed, email];
}

Expand Down Expand Up @@ -280,39 +266,6 @@ async function getPermissions(seed: Uint8Array, permissions: Permission[]): Prom
return permissionsResponse;
}

/**
* Connects to a portal account by either registering or logging in to an
* existing account. The resulting cookie will be set on the MySky domain and
* takes effect in Main MySky immediate.
*
* NOTE: Main MySky will register "auto re-login"; we don't have to do that
* here.
*
* @param seed - The user seed.
* @param email - The user email.
*/
async function connectToPortalAccount(seed: Uint8Array, email: string): Promise<void> {
// Register and get the JWT cookie.
//
// Make requests to login and register in parallel. At most one can succeed,
// and this saves a lot of time.
try {
await Promise.any([register(client, seed, email), login(client, seed, email)]);
} catch (e) {
throw new Error(`Could not register or login: ${e}`);
}
}

// TODO
/**
* If the email was provided by the user, save it in user settings.
*
* @returns - An empty promise.
*/
async function saveEmailInSettings(): Promise<void> {
return;
}

/**
* Gets the user's seed provider display URL if set, or the default.
*
Expand Down Expand Up @@ -494,6 +447,26 @@ async function setupAndRunDisplay<T>(displayUrl: string, methodName: string, ...
});
}

/**
* Waits for portal login on Main MySky to complete.
*/
async function waitForMySkyPortalLogin(): Promise<void> {
return new Promise((resolve, reject) =>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this might block forever, that's ok right? would've expected to see a timeout mechanism of sorts here

window.addEventListener("storage", async ({ key, newValue }: StorageEvent) => {
if (key !== PORTAL_LOGIN_COMPLETE_SENTINEL_KEY) {
return;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this makes it so promise1 never resolves, are we good with that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we only want the promise to resolve when the right storage key is encountered. Any other storage key shouldn't trigger a resolve.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we reject here, then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No! 😅 We don't want login to fail if a different key is set for whatever reason. If there is another storage event listener for that key, it will also be triggered. Here, we are only interested in the specific key we are listening for.

}

// Check for errors from Main MySky.
if (newValue !== "") {
reject(newValue);
}

resolve();
})
);
}

// =======
// Helpers
// =======
Expand All @@ -510,8 +483,9 @@ async function catchError(errorMsg: string): Promise<void> {

/**
* Stores the root seed and email in local storage. This triggers the storage
* event listener in the main invisible MySky frame. Main MySky needs the email
* so that it can login again when the JWT cookie expires.
* event listener in the main invisible MySky frame. This switches to the
* preferred portal, registers or logs in to the portal account and sets up
* login again when the JWT cookie expires. See `setUpStorageEventListener`.
*
* NOTE: If ENV == 'dev' the seed is salted before storage.
*
Expand Down
Loading