1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-14 07:13:32 +00:00
Files
browser/libs/common/src/state-migrations/migrations/3-fix-premium.ts
Matt Gibson 3340af8084 PM-3585 Improve state migrations (#5009)
* WIP: safer state migrations

Co-authored-by: Justin Baur <justindbaur@users.noreply.github.com>

* Add min version check and remove old migrations

Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com>

* Add rollback and version checking

* Add state version move migration

* Expand tests and improve typing for Migrations

* Remove StateMigration Service

* Rewrite version 5 and 6 migrations

* Add all but initial migration to supported migrations

* Handle stateVersion location in migrator update versions

* Move to unique migrations directory

* Disallow imports outside of state-migrations

* Lint and test fixes

* Do not run migrations if we cannot determine state

* Fix desktop background StateService build

* Document Migration builder class

* Add debug logging to migrations

* Comment on migrator overrides

* Use specific property names

* `npm run prettier` 🤖

* Insert new migration

* Set stateVersion when creating new globals object

* PR comments

* Fix migrate imports

* Move migration building into `migrate` function

* Export current version from migration definitions

* Move file version concerns to migrator

* Update migrate spec to reflect new version requirements

* Fix import paths

* Prefer unique state data

* Remove unnecessary async

* Prefer to not use `any`

---------

Co-authored-by: Justin Baur <justindbaur@users.noreply.github.com>
Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com>
2023-08-30 17:57:20 +00:00

49 lines
1.9 KiB
TypeScript

// eslint-disable-next-line import/no-restricted-paths -- Used for token decoding, which are valid for days. We want the latest
import { TokenService } from "../../auth/services/token.service";
import { MigrationHelper } from "../migration-helper";
import { Migrator, IRREVERSIBLE, Direction } from "../migrator";
type ExpectedAccountType = {
profile?: { hasPremiumPersonally?: boolean };
tokens?: { accessToken?: string };
};
export class FixPremiumMigrator extends Migrator<2, 3> {
async migrate(helper: MigrationHelper): Promise<void> {
const accounts = await helper.getAccounts<ExpectedAccountType>();
async function fixPremium(userId: string, account: ExpectedAccountType) {
if (account?.profile?.hasPremiumPersonally === null && account.tokens?.accessToken != null) {
let decodedToken: { premium: boolean };
try {
decodedToken = await TokenService.decodeToken(account.tokens.accessToken);
} catch {
return;
}
if (decodedToken?.premium == null) {
return;
}
account.profile.hasPremiumPersonally = decodedToken?.premium;
return helper.set(userId, account);
}
}
await Promise.all(accounts.map(({ userId, account }) => fixPremium(userId, account)));
}
rollback(helper: MigrationHelper): Promise<void> {
throw IRREVERSIBLE;
}
// Override is necessary because default implementation assumes `stateVersion` at the root, but for this version
// it is nested inside a global object.
override async updateVersion(helper: MigrationHelper, direction: Direction): Promise<void> {
const endVersion = direction === "up" ? this.toVersion : this.fromVersion;
helper.currentVersion = endVersion;
const global: Record<string, unknown> = (await helper.get("global")) || {};
await helper.set("global", { ...global, stateVersion: endVersion });
}
}