Skip to content

Commit

Permalink
Merge pull request #802 from MoralisWeb3/feat/auth-refactor
Browse files Browse the repository at this point in the history
Feat/auth refactor
  • Loading branch information
sogunshola authored Nov 15, 2022
2 parents d75f372 + 5eb0313 commit 9ca62a0
Show file tree
Hide file tree
Showing 22 changed files with 600 additions and 178 deletions.
2 changes: 1 addition & 1 deletion packages/auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"test:watch": "yarn run test --watch",
"lint": "eslint . --ext .js,.ts,.tsx,jsx",
"clean": "rm -rf lib && rm -rf tsconfig.tsbuildinfo && rm -rf tsconfig.build.tsbuildinfo && rm -rf ./node_modules/.cache/nx",
"gen:api-typeses": "openapi-typescript https://authapi.moralis.io/api-docs-json --output src/generated/types.ts",
"gen:api-types": "openapi-typescript https://authapi.moralis.io/api-docs-json --output src/generated/types.ts",
"build": "tsc -p tsconfig.build.json",
"dev": "tsc --watch"
},
Expand Down
8 changes: 4 additions & 4 deletions packages/auth/src/methods/requestMessage.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { SolAddressish, SolNetworkish, SolAddress, SolNetwork } from '@moralisweb3/common-sol-utils';
import { EndpointResolver } from '@moralisweb3/api-utils';
import { OperationResolver } from '@moralisweb3/api-utils';
import Core, { AuthErrorCode, MoralisAuthError } from '@moralisweb3/common-core';
import { EvmAddress, EvmAddressish, EvmChain, EvmChainish } from '@moralisweb3/common-evm-utils';
import { BASE_URL } from '../MoralisAuth';
import { initializeChallengeEvm, initializeChallengeSol } from '../resolvers';
import { AuthNetworkType } from '../utils/AuthNetworkType';
import { requestChallengeSolanaOperation, requestChallengeEvmOperation } from '../operations';

// Imported from Swagger and adjusted for better types for Evm
// TODO: generalize and extend generated types
Expand Down Expand Up @@ -51,7 +51,7 @@ const makeEvmRequestMessage = (
core: Core,
{ chain, address, networkType, network, ...options }: RequestMessageEvmOptions,
) => {
return EndpointResolver.create(core, BASE_URL, initializeChallengeEvm).fetch({
return new OperationResolver(requestChallengeEvmOperation, BASE_URL, core).fetch({
chainId: EvmChain.create(chain).apiId,
address: EvmAddress.create(address).checksum,
...options,
Expand All @@ -62,7 +62,7 @@ const makeSolRequestMessage = (
core: Core,
{ address, solNetwork, networkType, network, ...options }: RequestMessageSolOptions,
) => {
return EndpointResolver.create(core, BASE_URL, initializeChallengeSol).fetch({
return new OperationResolver(requestChallengeSolanaOperation, BASE_URL, core).fetch({
network: SolNetwork.create(solNetwork).network,
address: SolAddress.create(address).toString(),
...options,
Expand Down
8 changes: 4 additions & 4 deletions packages/auth/src/methods/verify.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { EndpointResolver } from '@moralisweb3/api-utils';
import { OperationResolver } from '@moralisweb3/api-utils';
import Core, { AuthErrorCode, MoralisAuthError } from '@moralisweb3/common-core';
import { BASE_URL } from '../MoralisAuth';
import { completeChallengeEvm, completeChallengeSol } from '../resolvers';
import { verifyChallengeSolanaOperation, verifyChallengeEvmOperation } from '../operations';
import { AuthNetworkType } from '../utils/AuthNetworkType';

export interface VerifyEvmOptions {
Expand Down Expand Up @@ -30,14 +30,14 @@ export type VerifyEvmData = ReturnType<typeof makeEvmVerify>;
export type VerifySolData = ReturnType<typeof makeSolVerify>;

const makeEvmVerify = (core: Core, { networkType, network, ...options }: VerifyEvmOptions) => {
return EndpointResolver.create(core, BASE_URL, completeChallengeEvm).fetch({
return new OperationResolver(verifyChallengeEvmOperation, BASE_URL, core).fetch({
message: options.message,
signature: options.signature,
});
};

const makeSolVerify = (core: Core, { networkType, network, ...options }: VerifySolOptions) => {
return EndpointResolver.create(core, BASE_URL, completeChallengeSol).fetch({
return new OperationResolver(verifyChallengeSolanaOperation, BASE_URL, core).fetch({
message: options.message,
signature: options.signature,
});
Expand Down
2 changes: 2 additions & 0 deletions packages/auth/src/operations/evm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './verifyChallengeEvmOperation';
export * from './requestChallengeEvmOperation';
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import MoralisCore from '@moralisweb3/common-core';
import { EvmAddress, EvmChain } from '@moralisweb3/common-evm-utils';
import { requestChallengeEvmOperation, RequestChallengeEvmRequest } from './requestChallengeEvmOperation';

describe('evmRequestChallengeOperation', () => {
let core: MoralisCore;

beforeAll(() => {
core = MoralisCore.create();
});

it('serializeRequest() serializes correctly and deserializeRequest() deserializes correctly', () => {
const address = '0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359';
const chain = '25';
const expirationTime = '2021-01-01T00:00:00.000Z';
const notBefore = '2020-01-01T00:00:00.000Z';

const request: Required<RequestChallengeEvmRequest> = {
address: EvmAddress.create(address, core),
domain: 'defi.finance',
chainId: EvmChain.create(chain, core),
statement: 'VALID_RESPONSE',
uri: 'https://defi.finance/',
expirationTime: new Date(expirationTime),
notBefore: new Date(notBefore),
resources: ['https://docs.moralis.io/'],
timeout: 50,
};

const serializedRequest = requestChallengeEvmOperation.serializeRequest(request, core);

expect(serializedRequest.address).toBe(address);
expect(serializedRequest.chainId).toBe(chain);
expect(serializedRequest.domain).toBe(request.domain);
expect(serializedRequest.statement).toBe(request.statement);
expect(serializedRequest.uri).toBe(request.uri);
expect(serializedRequest.expirationTime).toBe(request.expirationTime);
expect(serializedRequest.notBefore).toBe(request.notBefore);
expect(serializedRequest.resources).toBe(request.resources);
expect(serializedRequest.timeout).toBe(request.timeout);

const deserializedRequest = requestChallengeEvmOperation.deserializeRequest(serializedRequest, core);

expect((deserializedRequest.address as EvmAddress).checksum).toBe(address);
expect((deserializedRequest.chainId as EvmChain).decimal.toString()).toBe(chain);
expect(deserializedRequest.domain).toBe(request.domain);
expect(deserializedRequest.statement).toBe(request.statement);
expect(deserializedRequest.uri).toBe(request.uri);
expect(deserializedRequest.expirationTime).toBe(request.expirationTime);
expect(deserializedRequest.notBefore).toBe(request.notBefore);
expect(deserializedRequest.resources).toBe(request.resources);
expect(deserializedRequest.timeout).toBe(request.timeout);
});
});
109 changes: 109 additions & 0 deletions packages/auth/src/operations/evm/requestChallengeEvmOperation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { Core, Camelize, Operation, DateInput } from '@moralisweb3/common-core';
import { EvmAddress, EvmAddressish, EvmChainish, EvmChainResolver } from '@moralisweb3/common-evm-utils';
import { operations } from '../../generated/types';

type OperationId = 'requestChallengeEvm';

type BodyParams = operations[OperationId]['requestBody']['content']['application/json'];
type RequestParams = BodyParams;

type SuccessResponse = operations[OperationId]['responses']['201']['content']['application/json'];

// Exports

export interface RequestChallengeEvmRequest
extends Camelize<Omit<RequestParams, 'address' | 'chainId' | 'expirationTime' | 'notBefore'>> {
address: EvmAddressish;
chainId: EvmChainish;
expirationTime?: DateInput;
notBefore?: DateInput;
}

export type RequestChallengeEvmJSONRequest = ReturnType<typeof serializeRequest>;

export type RequestChallengeEvmJSONResponse = SuccessResponse;

export type RequestChallengeEvmResponse = ReturnType<typeof deserializeResponse>;

export const requestChallengeEvmOperation: Operation<
RequestChallengeEvmRequest,
RequestChallengeEvmJSONRequest,
RequestChallengeEvmResponse,
RequestChallengeEvmJSONResponse
> = {
method: 'POST',
name: 'requestChallengeEvm',
id: 'requestChallengeEvm',
groupName: 'evm',
urlPathPattern: '/challenge/request/evm',
bodyParamNames: [
'domain',
'chainId',
'address',
'statement',
'uri',
'expirationTime',
'notBefore',
'resources',
'timeout',
],
bodyType: 'properties',

getRequestUrlParams,
getRequestBody,
serializeRequest,
deserializeRequest,
deserializeResponse,
};

// Methods

function getRequestUrlParams() {
return {};
}

function getRequestBody(request: RequestChallengeEvmRequest, core: Core) {
return {
domain: request.domain,
chainId: EvmChainResolver.resolve(request.chainId, core).decimal.toString(),
address: EvmAddress.create(request.address, core).checksum,
statement: request.statement,
uri: request.uri,
expirationTime: request.expirationTime,
notBefore: request.notBefore,
resources: request.resources,
timeout: request.timeout,
};
}

function deserializeResponse(jsonResponse: RequestChallengeEvmJSONResponse) {
return jsonResponse;
}

function serializeRequest(request: RequestChallengeEvmRequest, core: Core) {
return {
domain: request.domain,
chainId: EvmChainResolver.resolve(request.chainId, core).decimal.toString(),
address: EvmAddress.create(request.address, core).checksum,
statement: request.statement,
uri: request.uri,
expirationTime: request.expirationTime,
notBefore: request.notBefore,
resources: request.resources,
timeout: request.timeout,
};
}

function deserializeRequest(jsonRequest: RequestChallengeEvmJSONRequest, core: Core): RequestChallengeEvmRequest {
return {
domain: jsonRequest.domain,
chainId: EvmChainResolver.resolve(jsonRequest.chainId, core),
address: EvmAddress.create(jsonRequest.address, core),
statement: jsonRequest.statement,
uri: jsonRequest.uri,
expirationTime: jsonRequest.expirationTime,
notBefore: jsonRequest.notBefore,
resources: jsonRequest.resources,
timeout: jsonRequest.timeout,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import MoralisCore from '@moralisweb3/common-core';
import { verifyChallengeEvmOperation, VerifyChallengeEvmJSONRequest } from './verifyChallengeEvmOperation';

describe('evmVerifyChallengeOperation', () => {
let core: MoralisCore;

beforeAll(() => {
core = MoralisCore.create();
});

it('serializeRequest() serializes correctly and deserializeRequest() deserializes correctly', () => {
const request: Required<VerifyChallengeEvmJSONRequest> = {
message: 'VALID_RESPONSE',
signature: '0x12345',
};

const serializedRequest = verifyChallengeEvmOperation.serializeRequest(request, core);

expect(serializedRequest.message).toBe(request.message);
expect(serializedRequest.signature).toBe(request.signature);

const deserializedRequest = verifyChallengeEvmOperation.deserializeRequest(serializedRequest, core);

expect(deserializedRequest.message).toBe(request.message);
expect(deserializedRequest.signature).toBe(request.signature);
});
});
78 changes: 78 additions & 0 deletions packages/auth/src/operations/evm/verifyChallengeEvmOperation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { Camelize, maybe, Operation } from '@moralisweb3/common-core';
import { EvmAddress, EvmChain } from '@moralisweb3/common-evm-utils';
import { operations } from '../../generated/types';

type OperationId = 'verifyChallengeEvm';

type BodyParams = operations[OperationId]['requestBody']['content']['application/json'];
type RequestParams = BodyParams;

type SuccessResponse = operations[OperationId]['responses']['201']['content']['application/json'];

// Exports

export interface VerifyChallengeEvmRequest extends Camelize<RequestParams> {}

export type VerifyChallengeEvmJSONRequest = ReturnType<typeof serializeRequest>;

export type VerifyChallengeEvmJSONResponse = SuccessResponse;

export type VerifyChallengeEvmResponse = ReturnType<typeof deserializeResponse>;

export const verifyChallengeEvmOperation: Operation<
VerifyChallengeEvmRequest,
VerifyChallengeEvmJSONRequest,
VerifyChallengeEvmResponse,
VerifyChallengeEvmJSONResponse
> = {
method: 'POST',
name: 'verifyChallengeEvm',
id: 'verifyChallengeEvm',
groupName: 'evm',
urlPathPattern: '/challenge/verify/evm',
bodyParamNames: ['message', 'signature'],
bodyType: 'properties',

getRequestUrlParams,
getRequestBody,
serializeRequest,
deserializeRequest,
deserializeResponse,
};

// Methods

function getRequestUrlParams() {
return {};
}

function getRequestBody(request: VerifyChallengeEvmRequest) {
return {
message: request.message,
signature: request.signature,
};
}

function deserializeResponse({ chainId, ...jsonResponse }: VerifyChallengeEvmJSONResponse) {
return {
...jsonResponse,
chain: EvmChain.create(chainId),
address: EvmAddress.create(jsonResponse.address),
expirationTime: maybe(jsonResponse.expirationTime, (value) => new Date(value)),
notBefore: maybe(jsonResponse.notBefore, (value) => new Date(value)),
};
}

function serializeRequest(request: VerifyChallengeEvmRequest) {
return {
message: request.message,
signature: request.signature,
};
}

function deserializeRequest(jsonRequest: VerifyChallengeEvmJSONRequest): VerifyChallengeEvmRequest {
return {
message: jsonRequest.message,
signature: jsonRequest.signature,
};
}
2 changes: 2 additions & 0 deletions packages/auth/src/operations/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './solana';
export * from './evm';
39 changes: 39 additions & 0 deletions packages/auth/src/operations/operations.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { toCamel } from '@moralisweb3/common-core';
import { OpenApiInterfaceReader, OperationDefinitionReader } from '@moralisweb3/test-utils';
import { operations } from './operations';

describe('operations', () => {
let reader: OpenApiInterfaceReader;

beforeAll(() => {
reader = new OpenApiInterfaceReader('src/generated/types.ts')!;
});

for (const operation of operations) {
describe(operation.name, () => {
it('defines all supported parameters', () => {
const openApiPathParamNames = reader.readOperationPathParamNames(operation.id)?.map(toCamel);
const openApiSearchParamNames = reader.readOperationSearchParamNames(operation.id)?.map(toCamel);
const openApiBodyParamNames = reader.readOperationRequestBodyParamNames(operation.id)?.map(toCamel);

expect(operation.urlPathParamNames?.sort().join(',')).toBe(openApiPathParamNames?.sort().join(','));
expect(operation.urlSearchParamNames?.sort().join(',')).toBe(openApiSearchParamNames?.sort().join(','));
expect(operation.bodyParamNames?.sort().join(',')).toBe(openApiBodyParamNames?.sort().join(','));
});

it(`getRequestUrlParams() function returns all supported property names`, () => {
const openApiPathParamNames = reader.readOperationPathParamNames(operation.id)?.map(toCamel);
const openApiSearchParamNames = reader.readOperationSearchParamNames(operation.id); // Must be same as in API

const definitionReader = new OperationDefinitionReader(
`src/operations/${operation.groupName}/${operation.name}Operation.ts`,
);
const returnPropertyNames = definitionReader.getRequestUrlParamsFunctionReturnPropertyNames();

const expectedPropertyNames = [...(openApiPathParamNames || []), ...(openApiSearchParamNames || [])];

expect(returnPropertyNames.sort().join(',')).toBe(expectedPropertyNames.sort().join(','));
});
});
}
});
9 changes: 9 additions & 0 deletions packages/auth/src/operations/operations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { requestChallengeEvmOperation, verifyChallengeEvmOperation } from './evm';
import { requestChallengeSolanaOperation, verifyChallengeSolanaOperation } from './solana';

export const operations = [
requestChallengeSolanaOperation,
requestChallengeEvmOperation,
verifyChallengeSolanaOperation,
verifyChallengeEvmOperation,
];
2 changes: 2 additions & 0 deletions packages/auth/src/operations/solana/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './verifyChallengeSolanaOperation';
export * from './requestChallengeSolanaOperation';
Loading

1 comment on commit 9ca62a0

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

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

Test coverage

Title Lines Statements Branches Functions
api-utils Coverage: 56%
56.43% (263/466) 43.85% (50/114) 57.73% (56/97)
auth Coverage: 90%
90.76% (118/130) 90.9% (20/22) 81.81% (36/44)
evm-api Coverage: 92%
92.72% (51/55) 66.66% (4/6) 81.25% (13/16)
common-evm-utils Coverage: 64%
64.98% (939/1445) 19.93% (123/617) 35.82% (201/561)
sol-api Coverage: 100%
100% (20/20) 66.66% (4/6) 100% (6/6)
common-sol-utils Coverage: 75%
74.86% (134/179) 63.15% (12/19) 65.67% (44/67)
common-streams-utils Coverage: 95%
95.6% (674/705) 97.93% (190/194) 100% (244/244)
streams Coverage: 87%
87.01% (563/647) 67.3% (70/104) 78.61% (136/173)

Please sign in to comment.