mirror of
https://github.com/logto-io/logto.git
synced 2025-02-24 22:05:56 -05:00
chore(connector-wechat*): fix wechat connectors error handler, comments and UTs (#1020)
* fix(connector-wechat*): remove unnecessary comments * fix(connector-wechat*): fix wechat connectors error handler, comments and UTs
This commit is contained in:
parent
458602fd64
commit
5a5083e863
6 changed files with 55 additions and 62 deletions
|
@ -57,15 +57,25 @@ describe('getAccessToken', () => {
|
||||||
expect(openid).toEqual('openid');
|
expect(openid).toEqual('openid');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws SocialAuthCodeInvalid error if accessToken not found in response', async () => {
|
it('throws SocialAuthCodeInvalid error if errcode is 40029', async () => {
|
||||||
nock(accessTokenEndpointUrl.origin)
|
nock(accessTokenEndpointUrl.origin)
|
||||||
.get(accessTokenEndpointUrl.pathname)
|
.get(accessTokenEndpointUrl.pathname)
|
||||||
.query(parameters)
|
.query(parameters)
|
||||||
.reply(200, {});
|
.reply(200, { errcode: 40_029, errmsg: 'invalid code' });
|
||||||
await expect(weChatNativeMethods.getAccessToken('code')).rejects.toMatchError(
|
await expect(weChatNativeMethods.getAccessToken('code')).rejects.toMatchError(
|
||||||
new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid)
|
new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('throws error if errcode is neither 40029 nor undefined', async () => {
|
||||||
|
nock(accessTokenEndpointUrl.origin)
|
||||||
|
.get(accessTokenEndpointUrl.pathname)
|
||||||
|
.query(true)
|
||||||
|
.reply(200, { errcode: 40_163, errmsg: 'invalid code' });
|
||||||
|
await expect(weChatNativeMethods.getAccessToken('wrong_code')).rejects.toMatchError(
|
||||||
|
new Error('invalid code')
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('validateConfig', () => {
|
describe('validateConfig', () => {
|
||||||
|
@ -140,15 +150,16 @@ describe('getUserInfo', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws error if `openid` is missing', async () => {
|
it('throws error if `openid` is missing', async () => {
|
||||||
nock.cleanAll();
|
|
||||||
nock(userInfoEndpointUrl.origin).get(userInfoEndpointUrl.pathname).query(parameters).reply(0, {
|
|
||||||
unionid: 'this_is_an_arbitrary_wechat_union_id',
|
|
||||||
headimgurl: 'https://github.com/images/error/octocat_happy.gif',
|
|
||||||
nickname: 'wechat bot',
|
|
||||||
});
|
|
||||||
nockNoOpenIdAccessTokenResponse();
|
nockNoOpenIdAccessTokenResponse();
|
||||||
|
nock(userInfoEndpointUrl.origin)
|
||||||
|
.get(userInfoEndpointUrl.pathname)
|
||||||
|
.query(parameters)
|
||||||
|
.reply(200, {
|
||||||
|
errcode: 41_009,
|
||||||
|
errmsg: 'missing openid',
|
||||||
|
});
|
||||||
await expect(weChatNativeMethods.getUserInfo({ code: 'code' })).rejects.toMatchError(
|
await expect(weChatNativeMethods.getUserInfo({ code: 'code' })).rejects.toMatchError(
|
||||||
new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid)
|
new Error('missing openid')
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -156,7 +167,7 @@ describe('getUserInfo', () => {
|
||||||
nock(userInfoEndpointUrl.origin)
|
nock(userInfoEndpointUrl.origin)
|
||||||
.get(userInfoEndpointUrl.pathname)
|
.get(userInfoEndpointUrl.pathname)
|
||||||
.query(parameters)
|
.query(parameters)
|
||||||
.reply(200, { errcode: 40_001 });
|
.reply(200, { errcode: 40_001, errmsg: 'invalid credential' });
|
||||||
await expect(weChatNativeMethods.getUserInfo({ code: 'code' })).rejects.toMatchError(
|
await expect(weChatNativeMethods.getUserInfo({ code: 'code' })).rejects.toMatchError(
|
||||||
new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid)
|
new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid)
|
||||||
);
|
);
|
||||||
|
|
|
@ -31,9 +31,6 @@ import {
|
||||||
WeChatNativeConfig,
|
WeChatNativeConfig,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
// As creating a WeChat Web/Mobile application needs a real App or Website record, the real test is temporarily not finished.
|
|
||||||
// TODO: test with our own wechat mobile/web application (LOG-1910), already tested with other verified wechat web application
|
|
||||||
|
|
||||||
export default class WeChatNativeConnector implements SocialConnector {
|
export default class WeChatNativeConnector implements SocialConnector {
|
||||||
public metadata: ConnectorMetadata = defaultMetadata;
|
public metadata: ConnectorMetadata = defaultMetadata;
|
||||||
|
|
||||||
|
@ -68,6 +65,7 @@ export default class WeChatNativeConnector implements SocialConnector {
|
||||||
access_token: accessToken,
|
access_token: accessToken,
|
||||||
openid,
|
openid,
|
||||||
errcode,
|
errcode,
|
||||||
|
errmsg,
|
||||||
} = await got
|
} = await got
|
||||||
.get(accessTokenEndpoint, {
|
.get(accessTokenEndpoint, {
|
||||||
searchParams: { appid, secret, code, grant_type: 'authorization_code' },
|
searchParams: { appid, secret, code, grant_type: 'authorization_code' },
|
||||||
|
@ -75,10 +73,8 @@ export default class WeChatNativeConnector implements SocialConnector {
|
||||||
})
|
})
|
||||||
.json<AccessTokenResponse>();
|
.json<AccessTokenResponse>();
|
||||||
|
|
||||||
assert(
|
assert(errcode !== 40_029, new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid));
|
||||||
errcode !== 40_029 && accessToken && openid,
|
assert(!errcode && accessToken && openid, new Error(errmsg ?? ''));
|
||||||
new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid)
|
|
||||||
);
|
|
||||||
|
|
||||||
return { accessToken, openid };
|
return { accessToken, openid };
|
||||||
};
|
};
|
||||||
|
@ -87,15 +83,6 @@ export default class WeChatNativeConnector implements SocialConnector {
|
||||||
const { code } = codeDataGuard.parse(data);
|
const { code } = codeDataGuard.parse(data);
|
||||||
const { accessToken, openid } = await this.getAccessToken(code);
|
const { accessToken, openid } = await this.getAccessToken(code);
|
||||||
|
|
||||||
// TO-DO: @Darcy refactor this
|
|
||||||
// 'openid' is defined as a required input argument in WeChat API doc, but it does not necessarily have to
|
|
||||||
// be the return value from getAccessToken per testing.
|
|
||||||
// In other words, 'openid' is required but the response of getUserInfo is consistent as long as
|
|
||||||
// access_token is valid.
|
|
||||||
// We are expecting to get 41009 'missing openid' response according to the developers doc, but the
|
|
||||||
// fact is that we still got 40001 'invalid credentials' response.
|
|
||||||
assert(openid, new Error('`openid` is required by WeChat API.'));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { unionid, headimgurl, nickname, errcode, errmsg } = await got
|
const { unionid, headimgurl, nickname, errcode, errmsg } = await got
|
||||||
.get(userInfoEndpoint, {
|
.get(userInfoEndpoint, {
|
||||||
|
|
|
@ -15,6 +15,7 @@ export type AccessTokenResponse = {
|
||||||
refresh_token?: string;
|
refresh_token?: string;
|
||||||
scope?: string;
|
scope?: string;
|
||||||
errcode?: number;
|
errcode?: number;
|
||||||
|
errmsg?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserInfoResponse = {
|
export type UserInfoResponse = {
|
||||||
|
|
|
@ -57,15 +57,25 @@ describe('getAccessToken', () => {
|
||||||
expect(openid).toEqual('openid');
|
expect(openid).toEqual('openid');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws SocialAuthCodeInvalid error if accessToken not found in response', async () => {
|
it('throws SocialAuthCodeInvalid error if errcode is 40029', async () => {
|
||||||
nock(accessTokenEndpointUrl.origin)
|
nock(accessTokenEndpointUrl.origin)
|
||||||
.get(accessTokenEndpointUrl.pathname)
|
.get(accessTokenEndpointUrl.pathname)
|
||||||
.query(parameters)
|
.query(parameters)
|
||||||
.reply(200, {});
|
.reply(200, { errcode: 40_029, errmsg: 'invalid code' });
|
||||||
await expect(weChatMethods.getAccessToken('code')).rejects.toMatchError(
|
await expect(weChatMethods.getAccessToken('code')).rejects.toMatchError(
|
||||||
new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid)
|
new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('throws error if errcode is neither 40029 nor undefined', async () => {
|
||||||
|
nock(accessTokenEndpointUrl.origin)
|
||||||
|
.get(accessTokenEndpointUrl.pathname)
|
||||||
|
.query(true)
|
||||||
|
.reply(200, { errcode: 40_163, errmsg: 'invalid code' });
|
||||||
|
await expect(weChatMethods.getAccessToken('wrong_code')).rejects.toMatchError(
|
||||||
|
new Error('invalid code')
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('validateConfig', () => {
|
describe('validateConfig', () => {
|
||||||
|
@ -84,18 +94,9 @@ describe('validateConfig', () => {
|
||||||
|
|
||||||
const nockNoOpenIdAccessTokenResponse = () => {
|
const nockNoOpenIdAccessTokenResponse = () => {
|
||||||
const accessTokenEndpointUrl = new URL(accessTokenEndpoint);
|
const accessTokenEndpointUrl = new URL(accessTokenEndpoint);
|
||||||
const parameters = new URLSearchParams({
|
nock(accessTokenEndpointUrl.origin).get(accessTokenEndpointUrl.pathname).query(true).reply(200, {
|
||||||
appid: '<app-id>',
|
access_token: 'access_token',
|
||||||
secret: '<app-secret>',
|
|
||||||
code: 'code',
|
|
||||||
grant_type: 'authorization_code',
|
|
||||||
});
|
});
|
||||||
nock(accessTokenEndpointUrl.origin)
|
|
||||||
.get(accessTokenEndpointUrl.pathname)
|
|
||||||
.query(parameters)
|
|
||||||
.reply(200, {
|
|
||||||
access_token: 'access_token',
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('getUserInfo', () => {
|
describe('getUserInfo', () => {
|
||||||
|
@ -107,6 +108,7 @@ describe('getUserInfo', () => {
|
||||||
code: 'code',
|
code: 'code',
|
||||||
grant_type: 'authorization_code',
|
grant_type: 'authorization_code',
|
||||||
});
|
});
|
||||||
|
|
||||||
nock(accessTokenEndpointUrl.origin)
|
nock(accessTokenEndpointUrl.origin)
|
||||||
.get(accessTokenEndpointUrl.pathname)
|
.get(accessTokenEndpointUrl.pathname)
|
||||||
.query(parameters)
|
.query(parameters)
|
||||||
|
@ -141,15 +143,16 @@ describe('getUserInfo', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws error if `openid` is missing', async () => {
|
it('throws error if `openid` is missing', async () => {
|
||||||
nock.cleanAll();
|
|
||||||
nock(userInfoEndpointUrl.origin).get(userInfoEndpointUrl.pathname).query(parameters).reply(0, {
|
|
||||||
unionid: 'this_is_an_arbitrary_wechat_union_id',
|
|
||||||
headimgurl: 'https://github.com/images/error/octocat_happy.gif',
|
|
||||||
nickname: 'wechat bot',
|
|
||||||
});
|
|
||||||
nockNoOpenIdAccessTokenResponse();
|
nockNoOpenIdAccessTokenResponse();
|
||||||
|
nock(userInfoEndpointUrl.origin)
|
||||||
|
.get(userInfoEndpointUrl.pathname)
|
||||||
|
.query(parameters)
|
||||||
|
.reply(200, {
|
||||||
|
errcode: 41_009,
|
||||||
|
errmsg: 'missing openid',
|
||||||
|
});
|
||||||
await expect(weChatMethods.getUserInfo({ code: 'code' })).rejects.toMatchError(
|
await expect(weChatMethods.getUserInfo({ code: 'code' })).rejects.toMatchError(
|
||||||
new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid)
|
new Error('missing openid')
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -157,7 +160,7 @@ describe('getUserInfo', () => {
|
||||||
nock(userInfoEndpointUrl.origin)
|
nock(userInfoEndpointUrl.origin)
|
||||||
.get(userInfoEndpointUrl.pathname)
|
.get(userInfoEndpointUrl.pathname)
|
||||||
.query(parameters)
|
.query(parameters)
|
||||||
.reply(200, { errcode: 40_001 });
|
.reply(200, { errcode: 40_001, errmsg: 'invalid credential' });
|
||||||
await expect(weChatMethods.getUserInfo({ code: 'code' })).rejects.toMatchError(
|
await expect(weChatMethods.getUserInfo({ code: 'code' })).rejects.toMatchError(
|
||||||
new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid)
|
new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid)
|
||||||
);
|
);
|
||||||
|
|
|
@ -28,7 +28,7 @@ import {
|
||||||
import { weChatConfigGuard, AccessTokenResponse, UserInfoResponse, WeChatConfig } from './types';
|
import { weChatConfigGuard, AccessTokenResponse, UserInfoResponse, WeChatConfig } from './types';
|
||||||
|
|
||||||
// As creating a WeChat Web/Mobile application needs a real App or Website record, the real test is temporarily not finished.
|
// As creating a WeChat Web/Mobile application needs a real App or Website record, the real test is temporarily not finished.
|
||||||
// TODO: test with our own wechat mobile/web application (LOG-1910), already tested with other verified wechat web application
|
// TODO: test with our own WeChat web application (LOG-2719), already tested with other verified WeChat web application
|
||||||
|
|
||||||
export default class WeChatConnector implements SocialConnector {
|
export default class WeChatConnector implements SocialConnector {
|
||||||
public metadata: ConnectorMetadata = defaultMetadata;
|
public metadata: ConnectorMetadata = defaultMetadata;
|
||||||
|
@ -64,6 +64,7 @@ export default class WeChatConnector implements SocialConnector {
|
||||||
access_token: accessToken,
|
access_token: accessToken,
|
||||||
openid,
|
openid,
|
||||||
errcode,
|
errcode,
|
||||||
|
errmsg,
|
||||||
} = await got
|
} = await got
|
||||||
.get(accessTokenEndpoint, {
|
.get(accessTokenEndpoint, {
|
||||||
searchParams: { appid, secret, code, grant_type: 'authorization_code' },
|
searchParams: { appid, secret, code, grant_type: 'authorization_code' },
|
||||||
|
@ -71,10 +72,8 @@ export default class WeChatConnector implements SocialConnector {
|
||||||
})
|
})
|
||||||
.json<AccessTokenResponse>();
|
.json<AccessTokenResponse>();
|
||||||
|
|
||||||
assert(
|
assert(errcode !== 40_029, new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid));
|
||||||
errcode !== 40_029 && accessToken && openid,
|
assert(!errcode && accessToken && openid, new Error(errmsg ?? ''));
|
||||||
new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid)
|
|
||||||
);
|
|
||||||
|
|
||||||
return { accessToken, openid };
|
return { accessToken, openid };
|
||||||
};
|
};
|
||||||
|
@ -83,15 +82,6 @@ export default class WeChatConnector implements SocialConnector {
|
||||||
const { code } = codeDataGuard.parse(data);
|
const { code } = codeDataGuard.parse(data);
|
||||||
const { accessToken, openid } = await this.getAccessToken(code);
|
const { accessToken, openid } = await this.getAccessToken(code);
|
||||||
|
|
||||||
// TO-DO: @Darcy refactor this
|
|
||||||
// 'openid' is defined as a required input argument in WeChat API doc, but it does not necessarily have to
|
|
||||||
// be the return value from getAccessToken per testing.
|
|
||||||
// In other words, 'openid' is required but the response of getUserInfo is consistent as long as
|
|
||||||
// access_token is valid.
|
|
||||||
// We are expecting to get 41009 'missing openid' response according to the developers doc, but the
|
|
||||||
// fact is that we still got 40001 'invalid credentials' response.
|
|
||||||
assert(openid, new Error('`openid` is required by WeChat API.'));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { unionid, headimgurl, nickname, errcode, errmsg } = await got
|
const { unionid, headimgurl, nickname, errcode, errmsg } = await got
|
||||||
.get(userInfoEndpoint, {
|
.get(userInfoEndpoint, {
|
||||||
|
@ -105,7 +95,7 @@ export default class WeChatConnector implements SocialConnector {
|
||||||
// 'errmsg' and 'errcode' turn to non-empty values or empty values at the same time. Hence, if 'errmsg' is non-empty then 'errcode' should be non-empty.
|
// 'errmsg' and 'errcode' turn to non-empty values or empty values at the same time. Hence, if 'errmsg' is non-empty then 'errcode' should be non-empty.
|
||||||
|
|
||||||
assert(errcode !== 40_001, new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid));
|
assert(errcode !== 40_001, new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid));
|
||||||
assert(!errcode, new Error(errmsg));
|
assert(!errcode, new Error(errmsg ?? ''));
|
||||||
|
|
||||||
return { id: unionid ?? openid, avatar: headimgurl, name: nickname };
|
return { id: unionid ?? openid, avatar: headimgurl, name: nickname };
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ export type AccessTokenResponse = {
|
||||||
refresh_token?: string;
|
refresh_token?: string;
|
||||||
scope?: string;
|
scope?: string;
|
||||||
errcode?: number;
|
errcode?: number;
|
||||||
|
errmsg?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserInfoResponse = {
|
export type UserInfoResponse = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue