polymorpher / one-wallet

1wallet | Modulo OTP Wallet - unconventional keyless, non-custodial wallet secured by Google Authenticator. EVM-compatible, smart contract operated, with composable security.
https://1wallet.crazy.one
Apache License 2.0
112 stars 47 forks source link

1wallet app library #73

Open polymorpher opened 3 years ago

polymorpher commented 3 years ago

1wallet app library

The library should allow developers to onboard a user who does not yet have a wallet, or connect a user’s existing wallet to their app. The library should allow the app to

  1. create a new wallet
  2. authenticate the user,
  3. retrieve a user’s wallet information, balance, and transaction history,
  4. perform a transfer
  5. authorize a request (by signature) that may have a time-limit on its validity
  6. revoke an existing authorization

Multiple methods of integration should be provided to developers, because apps may have different user interaction flow and onboarding processes. Some methods are more complex than others and may take weeks to develop the first version. Here, we list the proposed methods by how fast we can develop these methods and make them ready for developers.

Redirect

This method is ideal for web apps to work with web-based 1wallet (https://1wallet.crazy.one).

The user is redirected to a /request endpoint of the site hosting the wallet client (e.g. https://1wallet.crazy.one/request). The specific nature of the request would be specified by GET parameters, e.g. callback URL, app name, reason, action to be performed, any specific wallet, and more. The user would be able to choose a wallet (if one is not specified), inspect the request, and click a button to grant or deny the request. In either case, the user would be redirected back to the app itself.

If the request is granted, the callback would attach information necessary for the app to further process the request, e.g. signature and data, in cases of an authorization or authentication, or transaction id, in cases of a transfer, or just a wallet address, in cases of creating a new wallet. The information should be minimally sufficient. The library itself can perform most read operations (e.g. retrieving wallet information) without using Redirect or requesting an authorization.

Wallet Connect

This method is ideal for a mobile 1wallet client to connect with a web-based app. This is discussed in detail in Part IV of https://github.com/polymorpher/one-wallet/issues/5. In fact, its core mechanism and data flow is similar to Redirect method. Evaluating this method for a second time, I find its additional complexity is only justified in the narrow scope of mobile 1wallet client working with a web-based app, because Redirect method is significantly easier to implement for a web-to-web integration, and Redirect method can be similarly implemented for a scenario connecting mobile 1wallet to mobile based app: the app could use deep link to redirect to the 1wallet mobile app (or simply open a browser link which triggers the activation of the 1wallet mobile app), and the 1wallet mobile app can perform a callback similarly to the original app.

Import

This method is ideal for apps or other web clients that intend to function as a wallet, and to perform all operations such as transfer, authorization, and signing inside the app. In these operations, OTP would still be required from the user.

The process begins by the app asking the user (via a function call to the library) to select a local file previously exported from 1wallet that contains the state of the wallet and the proofs the wallet generated. For a complete export of a standard 1wallet that has a 1-year lifespan, the file should be around 64MB. The export can be a partial export, in which case it only contains proofs needed for a subset of time ranges, and the size of the file would be substantially less. After the user selects a file, the library would process the file and essentially generates a copy of the 1wallet inside the app, and store a copy of the proofs in IndexedDB under the app’s domain. The app can then use functions from the library to perform the desired operations (subject to user’s approval using OTPs). Note that, a large amount of implementation work should be expected by using this approach, since the app would essentially have to implement the UI and user interactions related to all the operations by the app itself. The app would be unable to leverage existing 1wallet UI as in the Redirect method. The library does not provide any UI either. It only provides the core functions.

We will add export functionality to our 1wallet client soon (https://1wallet.crazy.one)

IPFS

This method serves the purpose as in the Import method. The core mechanism of this method is similar to Import, except the proofs needed by the wallet at any given point of time would be dynamically loaded from IPFS. The app still needs to get one piece of information for the library: the hseed from the client. The hseed is necessary to produce the proof needed for every operation on the wallet. The hseed is 18-26 bytes long (e.g. a hexadecimal string of 36-52 characters long), depending on the setting and version of the wallet.

This method requires the IPFS version of the implementation of Scrambled Memory Layout (revised) (https://github.com/polymorpher/one-wallet/issues/63) to function. It may take some time before we can get to it and make it work reliability.

After the above implementation is complete, we will add a feature for the user to display and copy the hseed from our 1wallet client (https://1wallet.crazy.one).

givp commented 3 years ago

@polymorpher for the redirect option, I recommend borrowing concepts from OAuth2 protocol by making the handshake a multi-step process. Like OAuth, the redirect should obtain a temporary request token and then the client can use that to exchange with an access token to complete the transaction. It is obviously not identical but I see many "man in the middle" security holes if the redirect flow is not implemented correctly.

polymorpher commented 3 years ago

@polymorpher for the redirect option, I recommend borrowing concepts from OAuth2 protocol by making the handshake a multi-step process. Like OAuth, the redirect should obtain a temporary request token and then the client can use that to exchange with an access token to complete the transaction. It is obviously not identical but I see many "man in the middle" security holes if the redirect flow is not implemented correctly.

I thought about using OAuth2. The problems are the following. It would require the application developer to register the app with a central authority which manages and generates secrets for each application. The app would also be forced to bind with a particular client instead of the wallet, since the confidential OAuth token cannot be stored on the wallet - it has to be stored at the wallet client and has a short-lifespan.

A major difference between OAuth flow and the use cases here is that neither the app nor the wallet would be expected to do anything offline - the user is involved in every step, and no authorization token is issued to allow either the wallet or the app to do anything without the user's involvement. I think Redirect should be secure against attacks for the following reasons:

  1. The first redirect from the app to the wallet is secured by HTTPS. If the app redirects to a malicious URL, the malicious URL would not be able to perform use case (2)(4)(5)(6) because it cannot access the storage and state of the wallet which are associated with 1wallet.crazy.one.
    1. For use case (1), if the malicious URL creates a tampered wallet, the client library can detect the wallet's code hash is incorrect by retrieving and hashing the code using the returned wallet address. We cannot prevent a malicious URL from creating a untampered wallet, but neither can OAuth, and this scenario would be harmless.
  2. At the wallet, the user can inspect the request and verify the requested parameters. This and step 1 ensure the request is not tampered with.
  3. If the request generates a signature, the signature committed, produced, and stored on-chain will be only valid for the request. This applies to use case (2)(5)(6). The signature can also be validated by the app by performing read-only operation on-chain via the library.
  4. If the request performs some action and produces a transaction id (use case (4)) or an address (use case (1)), the transaction id can be validated similarly to step 3.
  5. Use case (3) does not require Redirect.
givp commented 3 years ago

Would be great to create a data flow diagram for the redirect solution.

stephen-tse commented 3 years ago

let's focus first on just the use case 6 (authorize a request). a tip jar demo as a single-page web app will be useful for our hackathon – even as dao peer bonus like yearn's https://coordinape.com. a helpful feature: no reauthorize for 30 mins for total 100 ONE tokens.

for ux or security flow, google "ethereum login" or "ethereum authentication" or "ethereum iframe". https://github.com/burner-wallet/burner-wallet-2 is a good reference, too.

polymorpher commented 3 years ago

Coordinape restricts access but the article linked on the site is informative: https://medium.com/iearn/decentralized-payroll-management-for-daos-b2252160c543

Yes, we can start with a quick tip jar demo based on (5) request authorization and (4) transfer

Dewansahil commented 3 years ago

@polymorpher have you checked out Atheneum app connection libraries? https://docs.authereum.com/integration

hypnagonia commented 3 years ago

when using redirect an application loses all non-persistent state

we can extend redirect approach providing developers conventional library with async methods

const address = await wallet.auth()

using cross tab communication https://github.com/pubkey/broadcast-channel

library on page A opens wallet's redirect url on new tab B on B wallet eventually redirects back to callback url library listens to location change and once it is callback url, emits data to other tabs (A) and self close (B) on page A library receives the crosstab event and returns the response to the app

so we can implement conventional wallet connect interfaces like https://github.com/WalletConnect/walletconnect-monorepo

polymorpher commented 3 years ago

Note: work is underway in various PRs. Also see documentation in https://github.com/polymorpher/one-wallet/wiki/App-Integration

saugion commented 2 years ago

This is a great project, I'm starting to develop an application based on Harmony and I'd really love to be able to integrate such a feature. Will follow this thread with lot of curiosity. Good luck!