diff --git a/src/providers/hive/auth.js b/src/providers/hive/auth.js index 254133989..35b0f9ae5 100644 --- a/src/providers/hive/auth.js +++ b/src/providers/hive/auth.js @@ -3,8 +3,8 @@ import sha256 from 'crypto-js/sha256'; import Config from 'react-native-config'; import get from 'lodash/get'; -import { cryptoUtils } from '@hiveio/dhive'; -import { getUser } from './dhive'; + +import { getDigitPinCode, getUser } from './dhive'; import { setUserData, setAuthStatus, @@ -64,17 +64,9 @@ export const login = async (username, password, isPinCodeOpen) => { } }); - // Prepare hivesigner code - const signer = (message) => { - const hash = cryptoUtils.sha256(message); - return new Promise((resolve) => { - const key = privateKeys.ownerKey || privateKeys.activeKey || privateKeys.postingKey; - const signedKey = key.sign(hash); - const signedStr = signedKey.toString(); - resolve(signedStr); - }); - }; - const code = await makeHsCode(account.name, signer); + + const signerPrivateKey = privateKeys.ownerKey || privateKeys.activeKey || privateKeys.postingKey + const code = await makeHsCode(account.name, signerPrivateKey); const scTokens = await getSCAccessToken(code); let jsonMetadata; @@ -411,3 +403,45 @@ const isLoggedInUser = async (username) => { } return false; }; + +/** + * This migration snippet is used to update access token for users logged in using masterKey + * accessToken is required for all ecency api calls even for non hivesigner users. + */ +export const migrateToMasterKeyWithAccessToken = async (account, pinHash) => { + + //get username, user local data from account; + const username = account.name; + const userData = account.local; + + if(userData.accessToken){ + //skipping migration as access token already preset; + return account; + } + + //decrypt password from local data + const pinCode = getDigitPinCode(pinHash); + const password = decryptKey(userData.masterKey, pinCode) + + // Set private keys of user + const privateKeys = getPrivateKeys(username, password); + + const signerPrivateKey = privateKeys.ownerKey || privateKeys.activeKey || privateKeys.postingKey + const code = await makeHsCode(account.name, signerPrivateKey); + const scTokens = await getSCAccessToken(code); + + await setSCAccount(scTokens); + const accessToken = scTokens.access_token; + + //update data + const localData = { + ...userData, + accessToken: encryptKey(accessToken, pinCode), + } + //update realm + await updateUserData(localData); + + //return account with update local data + account.local = localData + return account; +} diff --git a/src/screens/application/container/applicationContainer.js b/src/screens/application/container/applicationContainer.js index 04ecebfc7..c6d89aa60 100644 --- a/src/screens/application/container/applicationContainer.js +++ b/src/screens/application/container/applicationContainer.js @@ -42,7 +42,7 @@ import { setVersionForWelcomeModal, } from '../../../realm/realm'; import { getUser, getPost } from '../../../providers/hive/dhive'; -import { switchAccount } from '../../../providers/hive/auth'; +import { migrateToMasterKeyWithAccessToken, switchAccount } from '../../../providers/hive/auth'; import { setPushToken, markActivityAsRead } from '../../../providers/ecency/ecency'; import { navigate } from '../../../navigation/service'; @@ -632,21 +632,27 @@ class ApplicationContainer extends Component { }; _fetchUserDataFromDsteem = async (realmObject) => { - const { dispatch, intl } = this.props; + const { dispatch, intl, pinCode } = this.props; - await getUser(realmObject.username) - .then((accountData) => { - accountData.local = realmObject; + try{ + let accountData = await getUser(realmObject.username) + accountData.local = realmObject; - dispatch(updateCurrentAccount(accountData)); + //migration script for previously mast key based logged in user not having access token + if(realmObject.authType === AUTH_TYPE.MASTER_KEY && realmObject.accessToken === ''){ + accountData = await migrateToMasterKeyWithAccessToken(accountData, pinCode) + } + + dispatch(updateCurrentAccount(accountData)); + + this._connectNotificationServer(accountData.name); + + }catch(err){ + Alert.alert( + `${intl.formatMessage({ id: 'alert.fetch_error' })} \n${err.message.substr(0, 20)}`, + ); + } - this._connectNotificationServer(accountData.name); - }) - .catch((err) => { - Alert.alert( - `${intl.formatMessage({ id: 'alert.fetch_error' })} \n${err.message.substr(0, 20)}`, - ); - }); }; _getSettings = async () => { @@ -803,10 +809,15 @@ class ApplicationContainer extends Component { const accountData = await switchAccount(targetAccount.username); const realmData = await getUserDataWithUsername(targetAccount.username); - const _currentAccount = accountData; + let _currentAccount = accountData; _currentAccount.username = accountData.name; [_currentAccount.local] = realmData; + //migreate account to use access token for master key auth type + if(realmData.authType === AUTH_TYPE.MASTER_KEY && realmData.accessToken){ + _currentAccount = await migrateToMasterKeyWithAccessToken(_currentAccount, pinCode) + } + dispatch(updateCurrentAccount(_currentAccount)); }; diff --git a/src/utils/hive-signer-helper.ts b/src/utils/hive-signer-helper.ts index 16cbe4270..64f4ee46d 100644 --- a/src/utils/hive-signer-helper.ts +++ b/src/utils/hive-signer-helper.ts @@ -1,4 +1,5 @@ import { b64uEnc } from "./b64"; +import { cryptoUtils, PrivateKey } from '@hiveio/dhive'; export interface HiveSignerMessage { signed_message: { @@ -11,11 +12,20 @@ export interface HiveSignerMessage { } -export const makeHsCode = async (account: string, signer: (message: string) => Promise): Promise => { +export const makeHsCode = async (account: string, privateKey:PrivateKey): Promise => { const timestamp = new Date().getTime() / 1000; const messageObj: HiveSignerMessage = {signed_message: {type: 'code', app: "ecency.app"}, authors: [account], timestamp}; const message = JSON.stringify(messageObj); - const signature = await signer(message); + const signature = signer(message, privateKey); messageObj.signatures = [signature]; return b64uEnc(JSON.stringify(messageObj)); } + + +export const signer = (message:any, privateKey:PrivateKey) => { + const hash = cryptoUtils.sha256(message); + const key = privateKey; + const signedKey = key.sign(hash); + const signedStr = signedKey.toString(); + return signedStr +} \ No newline at end of file