Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MWA 2.0 Auth Repository #605

Merged
merged 8 commits into from
Nov 27, 2023
Merged

MWA 2.0 Auth Repository #605

merged 8 commits into from
Nov 27, 2023

Conversation

Funkatronics
Copy link
Contributor

@Funkatronics Funkatronics commented Nov 13, 2023

Updates the walletlib AuthDatabase to store new authorized account parameters (account icon, chains, features). Updates the database schema version from 5>6 and handles database migration.

This PR does not address multiple authorized accounts per auth token. those changes got too complex and will come in a future PR.

Testing database migration:

  • clean installed fakewallet built from v1.x branch
  • initiated several authorizations from fakedapp to fill the auth repository
  • upgraded fakewallet with build form this branch
  • verified that auth records were successfully migrated (using SQLiteDatabaseBrowser)

@Funkatronics Funkatronics changed the title [WIP] MWA 2.0 Auth Repository MWA 2.0 Auth Repository Nov 14, 2023
@@ -9,7 +9,7 @@
String COLUMN_AUTHORIZATIONS_ID = "id"; // type: int
String COLUMN_AUTHORIZATIONS_IDENTITY_ID = "identity_id"; // type: long
String COLUMN_AUTHORIZATIONS_ISSUED = "issued"; // type: long
String COLUMN_AUTHORIZATIONS_PUBLIC_KEY_ID = "public_key_id"; // type: long
String COLUMN_AUTHORIZATIONS_ACCOUNT_ID = "public_key_id"; // type: long
Copy link
Contributor

Choose a reason for hiding this comment

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

Is COLUMN_AUTHORIZATIONS_ACCOUNT_ID value suppose to be "public_key_id"? It's unchanged from the previous schema.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, good callout. this made it easy(easier) to migrate, as I don't need to migrate this column. This column will be changed again anyways when we move to multi account.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah ya know, now that I think about this more, I might not be handling migration of these ids correctly...

I am only migrating the publickey records over to the new AccountRecord but I do not actually update these ids. hmm. will get this fixed asap

Copy link
Contributor

Choose a reason for hiding this comment

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

Summarizing my understanding of the issue:

Pre-migrated databases will have an Authorizations Table with rows that contain a column (public_key_id) that contains a publicKeyId. When the migration step (onUpgrade) occurs, the Authorizations Table is not updated and the public_key_id column will still contain publicKeyIds rather than accountIds.

This is problematic because certain parts of code will assume that the column contains accountIds when they are actually still publicKeyIds. I'll add comments for spots where I see this being problematic.

Solutions:

  1. Create a new column for account_id in Authorizations Table then populate it during the migration step onUpgrade. Migrated DBs will just have a redundant public_key_id column that isn't used anymore.

  2. On upgrade/migration, alter each row in Authorizations Table so that public_key_id == account_id, by editing/updating each public_key_id value. (Is it possible to change a row's id? Where is the row's id even determined?).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The names of the columns does not really matter, as long as the name is respected in our code (the schema is not exposed publicly).

  1. we cant drop a column in SQLite but we can rename it. So rather than deleting the table and recreating it with the new schema, I opted to rename the public_key_id column to account_id then migrate the ids over. its maybe not the most ideal solution but it should work okay.
  2. I don't think we can change the primary key of a row in SQL. If we did, we'd also need to update all of the references on that ID. So I instead just updated the stored id for auth authorization record.

@@ -29,18 +35,35 @@ public void onConfigure(SQLiteDatabase db) {
public void onCreate(SQLiteDatabase db) {
db.execSQL(IdentityRecordSchema.CREATE_TABLE_IDENTITIES);
db.execSQL(AuthorizationsSchema.CREATE_TABLE_AUTHORIZATIONS);
db.execSQL(PublicKeysSchema.CREATE_TABLE_PUBLIC_KEYS);
db.execSQL(AccountRecordsSchema.CREATE_TABLE_ACCOUNTS);
db.execSQL(WalletUriBaseSchema.CREATE_TABLE_WALLET_URI_BASE);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Copy link
Contributor

Choose a reason for hiding this comment

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

When does onUpgrade trigger? Or, in other words, how does walletlib know when to onUpgrade the database?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

onUpgrade is called whenever the database schema version changes (5->6 in this case)

@NonNull @Size(min = 1)
public final AuthorizedAccount[] accounts;
@NonNull
public final AuthorizedAccount account;
Copy link
Contributor

Choose a reason for hiding this comment

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

Summarizing my understanding:

We're going from AuthorizedAccount[] to AuthorizedAccount because only the first item of the array was ever used anyways. Change it to a single account for clarity (until its actually implemented).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

in v1.x, this was never even an array, just a single public key and account label. the AuthorizedAccount struct was added in the 2.0 upgrade. This is reverting some of the original 2.0 changes to be single account tho for clarity, yes.

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class AccountRecordsDao extends DbContentProvider<AccountRecord>
Copy link
Contributor

Choose a reason for hiding this comment

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

Summarizing my understanding:

We're changing our "account" model from PublicKeyRecord -> AccountRecord because in MWA 2.0, the "account" model needs to be expanded to include chains/features/etc. A public key is now a part of the larger AccountRecord model.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yep exactly. adding new account metadata fields to the database.

having this already done will make it easier to migrate to multi-account too. we still need to store a list of AccountRecords for each authorization, but at least now the AccountRecord itself is there.

Copy link
Contributor

@Michaelsulistio Michaelsulistio left a comment

Choose a reason for hiding this comment

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

Had some more time to read through the changes and have a better understanding now. Left my reasoning in the comments, but please correct me if I have a misunderstanding!

" = " + TABLE_PUBLIC_KEYS + '.' + COLUMN_PUBLIC_KEYS_ID +
" INNER JOIN " + TABLE_ACCOUNTS +
" ON " + TABLE_AUTHORIZATIONS + '.' + COLUMN_AUTHORIZATIONS_ACCOUNT_ID +
" = " + TABLE_ACCOUNTS + '.' + COLUMN_ACCOUNTS_ID +
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. getAuthorizations() is incorrect if COLUMN_AUTHORIZATIONS_ACCOUNT_ID still refers to a publicKeyId.

The INNER_JOIN will try to match COLUMN_AUTHORIZATIONS_ACCOUNT_ID == COLUMN_ACCOUNTS_ID, but COLUMN_AUTHORIZATIONS_ACCOUNT_ID columns will all be publicKeyId values while its expecting accountId values. This results in an empty join.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed with migration from public_key_id column to account_id

@@ -9,7 +9,7 @@
String COLUMN_AUTHORIZATIONS_ID = "id"; // type: int
String COLUMN_AUTHORIZATIONS_IDENTITY_ID = "identity_id"; // type: long
String COLUMN_AUTHORIZATIONS_ISSUED = "issued"; // type: long
String COLUMN_AUTHORIZATIONS_PUBLIC_KEY_ID = "public_key_id"; // type: long
String COLUMN_AUTHORIZATIONS_ACCOUNT_ID = "public_key_id"; // type: long
Copy link
Contributor

Choose a reason for hiding this comment

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

Summarizing my understanding of the issue:

Pre-migrated databases will have an Authorizations Table with rows that contain a column (public_key_id) that contains a publicKeyId. When the migration step (onUpgrade) occurs, the Authorizations Table is not updated and the public_key_id column will still contain publicKeyIds rather than accountIds.

This is problematic because certain parts of code will assume that the column contains accountIds when they are actually still publicKeyIds. I'll add comments for spots where I see this being problematic.

Solutions:

  1. Create a new column for account_id in Authorizations Table then populate it during the migration step onUpgrade. Migrated DBs will just have a redundant public_key_id column that isn't used anymore.

  2. On upgrade/migration, alter each row in Authorizations Table so that public_key_id == account_id, by editing/updating each public_key_id value. (Is it possible to change a row's id? Where is the row's id even determined?).


@Override
public void deleteUnreferencedAccounts() {
final SQLiteStatement deleteUnreferencedPublicKeys = super.compileStatement(
Copy link
Contributor

Choose a reason for hiding this comment

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

deleteUnreferencedPublicKeys should be renamed to deleteUnreferencedAccounts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

final SQLiteStatement deleteUnreferencedPublicKeys = super.compileStatement(
"DELETE FROM " + TABLE_ACCOUNTS +
" WHERE " + COLUMN_ACCOUNTS_ID + " NOT IN " +
"(SELECT DISTINCT " + AuthorizationsSchema.COLUMN_AUTHORIZATIONS_ACCOUNT_ID +
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. Another problematic spot for migrated DBs in deleteUnreferencedAccounts.

COLUMN_ACCOUNTS_ID is expecting accountIds but AuthorizationsSchema.COLUMN_AUTHORIZATIONS_ACCOUNT_ID are still publicKeyIds.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed with migration from public_key_id column to account_id

@Funkatronics Funkatronics merged commit 5622b1c into main Nov 27, 2023
5 checks passed
@Funkatronics Funkatronics deleted the mwa-2.0-auth-repository branch November 27, 2023 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants