Page MenuHomePhabricator

D5603.id18443.diff
No OneTemporary

D5603.id18443.diff

diff --git a/keyserver/src/creators/account-creator.js b/keyserver/src/creators/account-creator.js
--- a/keyserver/src/creators/account-creator.js
+++ b/keyserver/src/creators/account-creator.js
@@ -94,9 +94,9 @@
? request.deviceTokenUpdateRequest.deviceToken
: viewer.deviceToken;
const [id] = await createIDs('users', 1);
- const newUserRow = [id, request.username, hash, time];
+ const newUserRow = [id, request.username, hash, time, request.address];
const newUserQuery = SQL`
- INSERT INTO users(id, username, hash, creation_time)
+ INSERT INTO users(id, username, hash, creation_time, ethereum_address)
VALUES ${[newUserRow]}
`;
const [userViewerData] = await Promise.all([
diff --git a/keyserver/src/endpoints.js b/keyserver/src/endpoints.js
--- a/keyserver/src/endpoints.js
+++ b/keyserver/src/endpoints.js
@@ -51,6 +51,7 @@
logInResponder,
oldPasswordUpdateResponder,
updateUserSettingsResponder,
+ siweResponder,
} from './responders/user-responders';
import { codeVerificationResponder } from './responders/verification-responders';
import { uploadDeletionResponder } from './uploads/uploads';
@@ -84,6 +85,7 @@
send_password_reset_email: sendPasswordResetEmailResponder,
send_verification_email: sendVerificationEmailResponder,
set_thread_unread_status: threadSetUnreadStatusResponder,
+ siwe: siweResponder,
update_account: passwordUpdateResponder,
update_activity: updateActivityResponder,
update_calendar_query: calendarQueryUpdateResponder,
diff --git a/keyserver/src/responders/user-responders.js b/keyserver/src/responders/user-responders.js
--- a/keyserver/src/responders/user-responders.js
+++ b/keyserver/src/responders/user-responders.js
@@ -1,6 +1,8 @@
// @flow
import invariant from 'invariant';
+import { SiweMessage, ErrorTypes } from 'siwe';
+// import { generateNonce } from 'siwe';
import t from 'tcomb';
import bcrypt from 'twin-bcrypt';
@@ -13,6 +15,8 @@
RegisterRequest,
LogInResponse,
LogInRequest,
+ SIWERequest,
+ SIWEResponse,
UpdatePasswordRequest,
UpdateUserSettingsRequest,
} from 'lib/types/account-types';
@@ -290,6 +294,130 @@
return response;
}
+// todo, see https://linear.app/comm/issue/ENG-2226/add-nonce-to-cookie-session
+// async function siweNonceResponder(viewer: Viewer) {
+// const nonce = generateNonce();
+// return nonce;
+// }
+
+const siweRequestInputValidator = tShape({
+ address: t.String,
+ signature: t.String,
+ message: t.String,
+ watchedIDs: t.list(t.String),
+ calendarQuery: t.maybe(entryQueryInputValidator),
+ deviceTokenUpdateRequest: t.maybe(deviceTokenUpdateRequestInputValidator),
+ platformDetails: tPlatformDetails,
+ source: t.maybe(t.enums.of(values(logInActionSources))),
+});
+
+async function siweResponder(
+ viewer: Viewer,
+ input: any,
+): Promise<SIWEResponse> {
+ await validateInput(viewer, siweRequestInputValidator, input);
+ const request: SIWERequest = input;
+
+ const { address, message, signature } = request;
+ const calendarQuery = request.calendarQuery
+ ? normalizeCalendarQuery(request.calendarQuery)
+ : null;
+ if (!address) {
+ throw new ServerError('invalid_parameters');
+ }
+
+ try {
+ const siweMessage = new SiweMessage(message);
+ await siweMessage.validate(signature);
+ } catch (error) {
+ switch (error) {
+ case ErrorTypes.EXPIRED_MESSAGE:
+ throw new ServerError('expired_signature', { status: 440 });
+ case ErrorTypes.INVALID_SIGNATURE:
+ throw new ServerError('invalid_signature', { status: 422 });
+ default:
+ throw new ServerError('oops', { status: 500 });
+ }
+ }
+
+ const userQuery = SQL`
+ SELECT id, hash, username
+ FROM users
+ WHERE ethereum_address = ${address}
+ `;
+ const [userResult] = await dbQuery(userQuery);
+ if (userResult.length === 0) {
+ // breaking out variables for flow's sake
+ const {
+ message: noop,
+ signature: noop2,
+ watchedIDs: noop3,
+ ...rest
+ } = request;
+ return await createAccount(viewer, {
+ username: address,
+ password: signature,
+ ...rest,
+ });
+ }
+ const userRow = userResult[0];
+ const id = userRow.id.toString();
+
+ const newServerTime = Date.now();
+ const deviceToken = request.deviceTokenUpdateRequest
+ ? request.deviceTokenUpdateRequest.deviceToken
+ : viewer.deviceToken;
+ const [userViewerData] = await Promise.all([
+ createNewUserCookie(id, {
+ platformDetails: request.platformDetails,
+ deviceToken,
+ }),
+ deleteCookie(viewer.cookieID),
+ ]);
+ viewer.setNewCookie(userViewerData);
+ if (calendarQuery) {
+ await setNewSession(viewer, calendarQuery, newServerTime);
+ }
+
+ const threadCursors = {};
+ // $FlowFixMe undefined [1] is incompatible with `$Iterable` [2].
+ for (const watchedThreadID of request.watchedIDs) {
+ threadCursors[watchedThreadID] = null;
+ }
+ const messageSelectionCriteria = { threadCursors, joinedThreads: true };
+
+ const [
+ threadsResult,
+ messagesResult,
+ entriesResult,
+ userInfos,
+ currentUserInfo,
+ ] = await Promise.all([
+ fetchThreadInfos(viewer),
+ fetchMessageInfos(viewer, messageSelectionCriteria, defaultNumberPerThread),
+ calendarQuery ? fetchEntryInfos(viewer, [calendarQuery]) : undefined,
+ fetchKnownUserInfos(viewer),
+ fetchLoggedInUserInfo(viewer),
+ ]);
+
+ const rawEntryInfos = entriesResult ? entriesResult.rawEntryInfos : null;
+ const response: LogInResponse = {
+ currentUserInfo,
+ rawMessageInfos: messagesResult.rawMessageInfos,
+ truncationStatuses: messagesResult.truncationStatuses,
+ serverTime: newServerTime,
+ userInfos: values(userInfos),
+ cookieChange: {
+ threadInfos: threadsResult.threadInfos,
+ userInfos: [],
+ },
+ };
+ if (rawEntryInfos) {
+ response.rawEntryInfos = rawEntryInfos;
+ }
+ return response;
+}
+
const updatePasswordRequestInputValidator = tShape({
code: t.String,
password: tPassword,
@@ -339,4 +467,5 @@
logInResponder,
oldPasswordUpdateResponder,
updateUserSettingsResponder,
+ siweResponder,
};
diff --git a/lib/actions/user-actions.js b/lib/actions/user-actions.js
--- a/lib/actions/user-actions.js
+++ b/lib/actions/user-actions.js
@@ -7,6 +7,8 @@
LogInResult,
RegisterResult,
RegisterInfo,
+ SIWEServerCall,
+ SIWEResult,
UpdateUserSettingsRequest,
} from '../types/account-types';
import type { GetSessionPublicKeysArgs } from '../types/request-types';
@@ -91,6 +93,33 @@
};
};
+const siweActionTypes = Object.freeze({
+ started: 'SIWE_STARTED',
+ success: 'SIWE_SUCCESS',
+ failed: 'SIWE_FAILED',
+});
+const siwe = (
+ callServerEndpoint: CallServerEndpoint,
+): ((siweInfo: SIWEServerCall) => Promise<SIWEResult>) => async siweInfo => {
+ const watchedIDs = threadWatcher.getWatchedIDs();
+ const response = await callServerEndpoint(
+ 'siwe',
+ {
+ ...siweInfo,
+ watchedIDs,
+ platformDetails: getConfig().platformDetails,
+ },
+ registerCallServerEndpointOptions,
+ );
+ return {
+ currentUserInfo: response.currentUserInfo,
+ rawMessageInfos: response.rawMessageInfos,
+ threadInfos: response.cookieChange.threadInfos,
+ userInfos: response.cookieChange.userInfos,
+ calendarQuery: siweInfo.calendarQuery,
+ };
+};
+
function mergeUserInfos(...userInfoArrays: UserInfo[][]): UserInfo[] {
const merged = {};
for (const userInfoArray of userInfoArrays) {
@@ -238,6 +267,8 @@
searchUsersActionTypes,
setUserSettings,
setUserSettingsActionTypes,
+ siwe,
+ siweActionTypes,
updateSubscription,
updateSubscriptionActionTypes,
};
diff --git a/lib/reducers/data-loaded-reducer.js b/lib/reducers/data-loaded-reducer.js
--- a/lib/reducers/data-loaded-reducer.js
+++ b/lib/reducers/data-loaded-reducer.js
@@ -5,6 +5,7 @@
deleteAccountActionTypes,
logInActionTypes,
registerActionTypes,
+ siweActionTypes,
} from '../actions/user-actions';
import type { BaseAction } from '../types/redux-types';
import { setNewSessionActionType } from '../utils/action-utils';
@@ -15,7 +16,8 @@
): boolean {
if (
action.type === logInActionTypes.success ||
- action.type === registerActionTypes.success
+ action.type === registerActionTypes.success ||
+ action.type === siweActionTypes.success
) {
return true;
} else if (
diff --git a/lib/reducers/user-reducer.js b/lib/reducers/user-reducer.js
--- a/lib/reducers/user-reducer.js
+++ b/lib/reducers/user-reducer.js
@@ -13,6 +13,7 @@
logInActionTypes,
registerActionTypes,
setUserSettingsActionTypes,
+ siweActionTypes,
} from '../actions/user-actions';
import type { BaseAction } from '../types/redux-types';
import {
@@ -45,6 +46,7 @@
if (
action.type === logInActionTypes.success ||
action.type === registerActionTypes.success ||
+ action.type === siweActionTypes.success ||
action.type === logOutActionTypes.success ||
action.type === deleteAccountActionTypes.success
) {
diff --git a/lib/types/account-types.js b/lib/types/account-types.js
--- a/lib/types/account-types.js
+++ b/lib/types/account-types.js
@@ -50,6 +50,7 @@
+calendarQuery?: ?CalendarQuery,
+deviceTokenUpdateRequest?: ?DeviceTokenUpdateRequest,
+platformDetails: PlatformDetails,
+ +address?: ?string,
};
export type RegisterResponse = {
@@ -140,6 +141,28 @@
+logInActionSource: LogInActionSource,
};
+export type SIWERequest = {
+ +address: string,
+ +message: string,
+ +signature: string,
+ +calendarQuery?: ?CalendarQuery,
+ +deviceTokenUpdateRequest?: ?DeviceTokenUpdateRequest,
+ +platformDetails: PlatformDetails,
+ +watchedIDs?: ?$ReadOnlyArray<string>,
+};
+
+export type SIWEServerCall = {
+ +address: string,
+ +message: string,
+ +signature: string,
+ ...LogInExtraInfo,
+};
+
+export type SIWEResponse = RegisterResponse | LogInResponse;
+
+export type SIWEResult = {
+ ...RegisterResult,
+};
export type UpdatePasswordRequest = {
code: string,
password: string,
diff --git a/lib/types/endpoints.js b/lib/types/endpoints.js
--- a/lib/types/endpoints.js
+++ b/lib/types/endpoints.js
@@ -24,6 +24,7 @@
CREATE_ACCOUNT: 'create_account',
LOG_IN: 'log_in',
UPDATE_PASSWORD: 'update_password',
+ SIWE: 'siwe',
});
type SessionChangingEndpoint = $Values<typeof sessionChangingEndpoints>;
diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js
--- a/lib/types/redux-types.js
+++ b/lib/types/redux-types.js
@@ -7,6 +7,7 @@
LogInResult,
RegisterResult,
DefaultNotificationPayload,
+ SIWEResult,
} from './account-types';
import type {
ActivityUpdateSuccessPayload,
@@ -818,6 +819,22 @@
+error: true,
+payload: Error,
+loadingInfo: LoadingInfo,
+ }
+ | {
+ +type: 'SIWE_STARTED',
+ +payload?: void,
+ +loadingInfo: LoadingInfo,
+ }
+ | {
+ +type: 'SIWE_SUCCESS',
+ +payload: SIWEResult,
+ +loadingInfo: LoadingInfo,
+ }
+ | {
+ +type: 'SIWE_FAILED',
+ +error: true,
+ +payload: Error,
+ +loadingInfo: LoadingInfo,
};
export type ActionPayload = ?(Object | Array<*> | $ReadOnlyArray<*> | string);
diff --git a/native/account/logged-out-modal.react.js b/native/account/logged-out-modal.react.js
--- a/native/account/logged-out-modal.react.js
+++ b/native/account/logged-out-modal.react.js
@@ -320,12 +320,14 @@
const promptButtonsSize = Platform.OS === 'ios' ? 40 : 61;
const logInContainerSize = 140;
const registerPanelSize = Platform.OS === 'ios' ? 181 : 180;
+ const siwePanelSize = 250;
const containerSize = add(
headerHeight,
cond(not(isPastPrompt(this.modeValue)), promptButtonsSize, 0),
cond(eq(this.modeValue, modeNumbers['log-in']), logInContainerSize, 0),
cond(eq(this.modeValue, modeNumbers['register']), registerPanelSize, 0),
+ cond(eq(this.modeValue, modeNumbers['siwe']), siwePanelSize, 0),
);
const potentialPanelPaddingTop = divide(
max(sub(this.contentHeight, this.keyboardHeightValue, containerSize), 0),
diff --git a/native/account/siwe-panel.react.js b/native/account/siwe-panel.react.js
--- a/native/account/siwe-panel.react.js
+++ b/native/account/siwe-panel.react.js
@@ -3,11 +3,11 @@
import Animated from 'react-native-reanimated';
import WebView from 'react-native-webview';
-import { registerActionTypes, register } from 'lib/actions/user-actions';
+import { siweActionTypes, siwe } from 'lib/actions/user-actions';
import type {
- RegisterInfo,
+ SIWEServerCall,
+ SIWEResult,
LogInExtraInfo,
- RegisterResult,
LogInStartingPayload,
} from 'lib/types/account-types';
import {
@@ -20,7 +20,6 @@
import { useSelector } from '../redux/redux-utils';
import { nativeLogInExtraInfoSelector } from '../selectors/account-selectors';
import { defaultLandingURLPrefix } from '../utils/url-utils';
-import { setNativeCredentials } from './native-credentials';
const commSIWE = `${defaultLandingURLPrefix}/siwe`;
@@ -35,40 +34,40 @@
// Redux dispatch functions
+dispatchActionPromise: DispatchActionPromise,
// async functions that hit server APIs
- +registerAction: (registerInfo: RegisterInfo) => Promise<RegisterResult>,
+ +siweAction: (siweInfo: SIWEServerCall) => Promise<SIWEResult>,
};
function SIWEPanel({
logInExtraInfo,
dispatchActionPromise,
- registerAction,
+ siweAction,
}: Props) {
const handleSIWE = React.useCallback(
- ({ address, signature }) => {
+ ({ address, message, signature }) => {
// this is all mocked from register-panel
const extraInfo = logInExtraInfo();
dispatchActionPromise(
- registerActionTypes,
- registerAction({
- username: address,
- password: signature,
+ siweActionTypes,
+ siweAction({
+ address,
+ message,
+ signature,
...extraInfo,
}),
undefined,
({ calendarQuery: extraInfo.calendarQuery }: LogInStartingPayload),
);
- setNativeCredentials({ username: address, password: signature });
},
- [logInExtraInfo, dispatchActionPromise, registerAction],
+ [logInExtraInfo, dispatchActionPromise, siweAction],
);
const handleMessage = React.useCallback(
event => {
const {
nativeEvent: { data },
} = event;
- const { address, signature } = JSON.parse(data);
+ const { address, message, signature } = JSON.parse(data);
if (address && signature) {
- handleSIWE({ address, signature });
+ handleSIWE({ address, message, signature });
}
},
[handleSIWE],
@@ -87,14 +86,14 @@
);
const dispatchActionPromise = useDispatchActionPromise();
- const callRegister = useServerCall(register);
+ const callSiwe = useServerCall(siwe);
return (
<SIWEPanel
{...props}
logInExtraInfo={logInExtraInfo}
dispatchActionPromise={dispatchActionPromise}
- registerAction={callRegister}
+ siweAction={callSiwe}
/>
);
},
diff --git a/native/utils/url-utils.js b/native/utils/url-utils.js
--- a/native/utils/url-utils.js
+++ b/native/utils/url-utils.js
@@ -40,7 +40,12 @@
return getDevNodeServerURLFromHostname(hostname);
}
+const canRainbowKitSignOverHTTPYet = false;
+
function getDevLandingURL(): string {
+ if (!canRainbowKitSignOverHTTPYet) {
+ return productionLandingURL;
+ }
invariant(__DEV__, 'getDevLandingURL called from production');
const hostname = getDevServerHostname();
return getDevLandingURLFromHostname(hostname);

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 26, 3:51 AM (12 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2582683
Default Alt Text
D5603.id18443.diff (15 KB)

Event Timeline