external-account.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import { ErrorV3 } from '@growi/core/dist/models';
  2. import { LoginErrorCode } from '~/interfaces/errors/login-error';
  3. import loggerFactory from '~/utils/logger';
  4. import { NullUsernameToBeRegisteredError } from '../models/errors';
  5. import ExternalAccount, { ExternalAccountDocument } from '../models/external-account';
  6. import PassportService from './passport';
  7. const logger = loggerFactory('growi:service:external-account-service');
  8. class ExternalAccountService {
  9. passportService: PassportService;
  10. // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
  11. constructor(passportService: PassportService) {
  12. this.passportService = passportService;
  13. }
  14. async getOrCreateUser(
  15. userInfo: {id: string, username: string, name?: string, email?: string},
  16. providerId: string,
  17. ): Promise<ExternalAccountDocument | undefined> {
  18. // get option
  19. const isSameUsernameTreatedAsIdenticalUser = this.passportService.isSameUsernameTreatedAsIdenticalUser(providerId);
  20. const isSameEmailTreatedAsIdenticalUser = this.passportService.isSameEmailTreatedAsIdenticalUser(providerId);
  21. try {
  22. // find or register(create) user
  23. const externalAccount = await ExternalAccount.findOrRegister(
  24. isSameUsernameTreatedAsIdenticalUser,
  25. isSameEmailTreatedAsIdenticalUser,
  26. providerId,
  27. userInfo.id,
  28. userInfo.username,
  29. userInfo.name,
  30. userInfo.email,
  31. );
  32. return externalAccount;
  33. }
  34. catch (err) {
  35. if (err instanceof NullUsernameToBeRegisteredError) {
  36. logger.error(err.message);
  37. throw new ErrorV3(err.message);
  38. }
  39. else if (err.name === 'DuplicatedUsernameException') {
  40. if (isSameEmailTreatedAsIdenticalUser || isSameUsernameTreatedAsIdenticalUser) {
  41. // associate to existing user
  42. logger.debug(`ExternalAccount '${userInfo.username}' will be created and bound to the exisiting User account`);
  43. return ExternalAccount.associate(providerId, userInfo.id, err.user);
  44. }
  45. logger.error('provider-DuplicatedUsernameException', providerId);
  46. throw new ErrorV3('message.provider_duplicated_username_exception', LoginErrorCode.PROVIDER_DUPLICATED_USERNAME_EXCEPTION,
  47. undefined, { failedProviderForDuplicatedUsernameException: providerId });
  48. }
  49. else if (err.name === 'UserUpperLimitException') {
  50. logger.error(err.message);
  51. throw new ErrorV3(err.message);
  52. }
  53. }
  54. }
  55. }
  56. // eslint-disable-next-line import/no-mutable-exports
  57. export let externalAccountService: ExternalAccountService | undefined; // singleton instance
  58. export function instanciate(passportService: PassportService): void {
  59. externalAccountService = new ExternalAccountService(passportService);
  60. }