@things-factory/auth-base 8.0.0-beta.8 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/client/actions/auth.ts +24 -0
  2. package/client/auth.ts +272 -0
  3. package/client/bootstrap.ts +47 -0
  4. package/client/directive/privileged.ts +28 -0
  5. package/client/index.ts +3 -0
  6. package/client/profiled.ts +83 -0
  7. package/client/reducers/auth.ts +31 -0
  8. package/dist-client/index.d.ts +0 -1
  9. package/dist-client/index.js +0 -1
  10. package/dist-client/index.js.map +1 -1
  11. package/dist-client/tsconfig.tsbuildinfo +1 -1
  12. package/dist-server/constants/error-code.d.ts +0 -2
  13. package/dist-server/constants/error-code.js +1 -3
  14. package/dist-server/constants/error-code.js.map +1 -1
  15. package/dist-server/controllers/change-pwd.js +2 -2
  16. package/dist-server/controllers/change-pwd.js.map +1 -1
  17. package/dist-server/controllers/delete-user.js +12 -13
  18. package/dist-server/controllers/delete-user.js.map +1 -1
  19. package/dist-server/controllers/invitation.d.ts +1 -2
  20. package/dist-server/controllers/invitation.js +5 -30
  21. package/dist-server/controllers/invitation.js.map +1 -1
  22. package/dist-server/controllers/profile.d.ts +3 -4
  23. package/dist-server/controllers/profile.js +2 -20
  24. package/dist-server/controllers/profile.js.map +1 -1
  25. package/dist-server/controllers/signin.d.ts +1 -4
  26. package/dist-server/controllers/signin.js +1 -17
  27. package/dist-server/controllers/signin.js.map +1 -1
  28. package/dist-server/controllers/signup.js +4 -13
  29. package/dist-server/controllers/signup.js.map +1 -1
  30. package/dist-server/controllers/unlock-user.js +0 -1
  31. package/dist-server/controllers/unlock-user.js.map +1 -1
  32. package/dist-server/controllers/verification.js +0 -1
  33. package/dist-server/controllers/verification.js.map +1 -1
  34. package/dist-server/middlewares/signin-middleware.js +4 -9
  35. package/dist-server/middlewares/signin-middleware.js.map +1 -1
  36. package/dist-server/middlewares/webauthn-middleware.js.map +1 -1
  37. package/dist-server/migrations/1548206416130-SeedUser.js +1 -2
  38. package/dist-server/migrations/1548206416130-SeedUser.js.map +1 -1
  39. package/dist-server/router/auth-checkin-router.js +2 -8
  40. package/dist-server/router/auth-checkin-router.js.map +1 -1
  41. package/dist-server/router/auth-private-process-router.js +7 -12
  42. package/dist-server/router/auth-private-process-router.js.map +1 -1
  43. package/dist-server/router/auth-public-process-router.js +9 -20
  44. package/dist-server/router/auth-public-process-router.js.map +1 -1
  45. package/dist-server/router/auth-signin-router.js +3 -3
  46. package/dist-server/router/auth-signin-router.js.map +1 -1
  47. package/dist-server/router/webauthn-router.js +1 -51
  48. package/dist-server/router/webauthn-router.js.map +1 -1
  49. package/dist-server/service/invitation/invitation-mutation.d.ts +2 -3
  50. package/dist-server/service/invitation/invitation-mutation.js +8 -20
  51. package/dist-server/service/invitation/invitation-mutation.js.map +1 -1
  52. package/dist-server/service/user/user-mutation.d.ts +9 -10
  53. package/dist-server/service/user/user-mutation.js +54 -112
  54. package/dist-server/service/user/user-mutation.js.map +1 -1
  55. package/dist-server/service/user/user-types.d.ts +0 -1
  56. package/dist-server/service/user/user-types.js +0 -4
  57. package/dist-server/service/user/user-types.js.map +1 -1
  58. package/dist-server/service/user/user.d.ts +0 -1
  59. package/dist-server/service/user/user.js +14 -40
  60. package/dist-server/service/user/user.js.map +1 -1
  61. package/dist-server/templates/account-unlock-email.d.ts +1 -2
  62. package/dist-server/templates/account-unlock-email.js +1 -1
  63. package/dist-server/templates/account-unlock-email.js.map +1 -1
  64. package/dist-server/templates/invitation-email.d.ts +1 -2
  65. package/dist-server/templates/invitation-email.js +1 -1
  66. package/dist-server/templates/invitation-email.js.map +1 -1
  67. package/dist-server/templates/verification-email.d.ts +1 -2
  68. package/dist-server/templates/verification-email.js +1 -1
  69. package/dist-server/templates/verification-email.js.map +1 -1
  70. package/dist-server/tsconfig.tsbuildinfo +1 -1
  71. package/package.json +6 -6
  72. package/server/constants/error-code.ts +20 -0
  73. package/server/constants/error-message.ts +0 -0
  74. package/server/constants/max-age.ts +1 -0
  75. package/server/controllers/auth.ts +5 -0
  76. package/server/controllers/change-pwd.ts +99 -0
  77. package/server/controllers/checkin.ts +21 -0
  78. package/server/controllers/delete-user.ts +68 -0
  79. package/server/controllers/invitation.ts +132 -0
  80. package/server/controllers/profile.ts +28 -0
  81. package/server/controllers/reset-password.ts +126 -0
  82. package/server/controllers/signin.ts +79 -0
  83. package/server/controllers/signup.ts +60 -0
  84. package/server/controllers/unlock-user.ts +61 -0
  85. package/server/controllers/utils/make-invitation-token.ts +5 -0
  86. package/server/controllers/utils/make-verification-token.ts +4 -0
  87. package/server/controllers/utils/password-rule.ts +120 -0
  88. package/server/controllers/utils/save-invitation-token.ts +10 -0
  89. package/server/controllers/utils/save-verification-token.ts +12 -0
  90. package/server/controllers/verification.ts +83 -0
  91. package/server/errors/auth-error.ts +24 -0
  92. package/server/errors/index.ts +2 -0
  93. package/server/errors/user-domain-not-match-error.ts +29 -0
  94. package/server/index.ts +37 -0
  95. package/server/middlewares/authenticate-401-middleware.ts +114 -0
  96. package/server/middlewares/domain-authenticate-middleware.ts +78 -0
  97. package/server/middlewares/graphql-authenticate-middleware.ts +13 -0
  98. package/server/middlewares/index.ts +67 -0
  99. package/server/middlewares/jwt-authenticate-middleware.ts +84 -0
  100. package/server/middlewares/signin-middleware.ts +55 -0
  101. package/server/middlewares/webauthn-middleware.ts +127 -0
  102. package/server/migrations/1548206416130-SeedUser.ts +59 -0
  103. package/server/migrations/1566805283882-SeedPrivilege.ts +28 -0
  104. package/server/migrations/index.ts +9 -0
  105. package/server/router/auth-checkin-router.ts +107 -0
  106. package/server/router/auth-private-process-router.ts +107 -0
  107. package/server/router/auth-public-process-router.ts +302 -0
  108. package/server/router/auth-signin-router.ts +55 -0
  109. package/server/router/auth-signup-router.ts +95 -0
  110. package/server/router/index.ts +9 -0
  111. package/server/router/oauth2/index.ts +2 -0
  112. package/server/router/oauth2/oauth2-authorize-router.ts +81 -0
  113. package/server/router/oauth2/oauth2-router.ts +165 -0
  114. package/server/router/oauth2/oauth2-server.ts +262 -0
  115. package/server/router/oauth2/passport-oauth2-client-password.ts +87 -0
  116. package/server/router/oauth2/passport-refresh-token.ts +87 -0
  117. package/server/router/path-base-domain-router.ts +8 -0
  118. package/server/router/site-root-router.ts +48 -0
  119. package/server/router/webauthn-router.ts +87 -0
  120. package/server/routes.ts +80 -0
  121. package/server/service/app-binding/app-binding-mutation.ts +22 -0
  122. package/server/service/app-binding/app-binding-query.ts +92 -0
  123. package/server/service/app-binding/app-binding-types.ts +11 -0
  124. package/server/service/app-binding/app-binding.ts +17 -0
  125. package/server/service/app-binding/index.ts +4 -0
  126. package/server/service/appliance/appliance-mutation.ts +113 -0
  127. package/server/service/appliance/appliance-query.ts +76 -0
  128. package/server/service/appliance/appliance-types.ts +56 -0
  129. package/server/service/appliance/appliance.ts +133 -0
  130. package/server/service/appliance/index.ts +6 -0
  131. package/server/service/application/application-mutation.ts +104 -0
  132. package/server/service/application/application-query.ts +98 -0
  133. package/server/service/application/application-types.ts +76 -0
  134. package/server/service/application/application.ts +216 -0
  135. package/server/service/application/index.ts +6 -0
  136. package/server/service/auth-provider/auth-provider-mutation.ts +159 -0
  137. package/server/service/auth-provider/auth-provider-parameter-spec.ts +24 -0
  138. package/server/service/auth-provider/auth-provider-query.ts +88 -0
  139. package/server/service/auth-provider/auth-provider-type.ts +67 -0
  140. package/server/service/auth-provider/auth-provider.ts +155 -0
  141. package/server/service/auth-provider/index.ts +7 -0
  142. package/server/service/domain-generator/domain-generator-mutation.ts +117 -0
  143. package/server/service/domain-generator/domain-generator-types.ts +46 -0
  144. package/server/service/domain-generator/index.ts +3 -0
  145. package/server/service/granted-role/granted-role-mutation.ts +156 -0
  146. package/server/service/granted-role/granted-role-query.ts +60 -0
  147. package/server/service/granted-role/granted-role.ts +27 -0
  148. package/server/service/granted-role/index.ts +6 -0
  149. package/server/service/index.ts +90 -0
  150. package/server/service/invitation/index.ts +6 -0
  151. package/server/service/invitation/invitation-mutation.ts +63 -0
  152. package/server/service/invitation/invitation-query.ts +33 -0
  153. package/server/service/invitation/invitation-types.ts +11 -0
  154. package/server/service/invitation/invitation.ts +63 -0
  155. package/server/service/login-history/index.ts +5 -0
  156. package/server/service/login-history/login-history-query.ts +51 -0
  157. package/server/service/login-history/login-history-type.ts +12 -0
  158. package/server/service/login-history/login-history.ts +45 -0
  159. package/server/service/partner/index.ts +6 -0
  160. package/server/service/partner/partner-mutation.ts +61 -0
  161. package/server/service/partner/partner-query.ts +102 -0
  162. package/server/service/partner/partner-types.ts +11 -0
  163. package/server/service/partner/partner.ts +57 -0
  164. package/server/service/password-history/index.ts +3 -0
  165. package/server/service/password-history/password-history.ts +16 -0
  166. package/server/service/privilege/index.ts +6 -0
  167. package/server/service/privilege/privilege-directive.ts +77 -0
  168. package/server/service/privilege/privilege-mutation.ts +92 -0
  169. package/server/service/privilege/privilege-query.ts +94 -0
  170. package/server/service/privilege/privilege-types.ts +60 -0
  171. package/server/service/privilege/privilege.ts +102 -0
  172. package/server/service/role/index.ts +6 -0
  173. package/server/service/role/role-mutation.ts +109 -0
  174. package/server/service/role/role-query.ts +155 -0
  175. package/server/service/role/role-types.ts +81 -0
  176. package/server/service/role/role.ts +72 -0
  177. package/server/service/user/domain-query.ts +24 -0
  178. package/server/service/user/index.ts +7 -0
  179. package/server/service/user/user-mutation.ts +413 -0
  180. package/server/service/user/user-query.ts +145 -0
  181. package/server/service/user/user-types.ts +97 -0
  182. package/server/service/user/user.ts +354 -0
  183. package/server/service/users-auth-providers/index.ts +5 -0
  184. package/server/service/users-auth-providers/users-auth-providers.ts +71 -0
  185. package/server/service/verification-token/index.ts +3 -0
  186. package/server/service/verification-token/verification-token.ts +60 -0
  187. package/server/service/web-auth-credential/index.ts +3 -0
  188. package/server/service/web-auth-credential/web-auth-credential.ts +67 -0
  189. package/server/templates/account-unlock-email.ts +65 -0
  190. package/server/templates/invitation-email.ts +66 -0
  191. package/server/templates/reset-password-email.ts +65 -0
  192. package/server/templates/verification-email.ts +66 -0
  193. package/server/types.ts +21 -0
  194. package/server/utils/accepts.ts +11 -0
  195. package/server/utils/access-token-cookie.ts +61 -0
  196. package/server/utils/check-permission.ts +52 -0
  197. package/server/utils/check-user-belongs-domain.ts +19 -0
  198. package/server/utils/check-user-has-role.ts +29 -0
  199. package/server/utils/encrypt-state.ts +22 -0
  200. package/server/utils/get-aes-256-key.ts +13 -0
  201. package/server/utils/get-domain-from-hostname.ts +7 -0
  202. package/server/utils/get-domain-users.ts +38 -0
  203. package/server/utils/get-secret.ts +13 -0
  204. package/server/utils/get-user-domains.ts +112 -0
  205. package/translations/en.json +1 -5
  206. package/translations/ja.json +1 -5
  207. package/translations/ko.json +3 -6
  208. package/translations/ms.json +1 -5
  209. package/translations/zh.json +1 -5
  210. package/dist-client/verify-webauthn.d.ts +0 -13
  211. package/dist-client/verify-webauthn.js +0 -72
  212. package/dist-client/verify-webauthn.js.map +0 -1
@@ -0,0 +1,84 @@
1
+ import passport from 'koa-passport'
2
+ import { ExtractJwt, Strategy as JWTstrategy } from 'passport-jwt'
3
+
4
+ import { config } from '@things-factory/env'
5
+
6
+ import { makeVerificationToken } from '../controllers/utils/make-verification-token'
7
+ import { saveVerificationToken } from '../controllers/utils/save-verification-token'
8
+ import { User, UserStatus } from '../service/user/user'
9
+ import { VerificationTokenType } from '../service/verification-token/verification-token'
10
+ import { clearAccessTokenCookie, getAccessTokenCookie, setAccessTokenCookie } from '../utils/access-token-cookie'
11
+ import { SECRET } from '../utils/get-secret'
12
+
13
+ const sessionExpiryPolicy = config.get('session/expiryPolicy', 'fixed')
14
+
15
+ passport.use(
16
+ new JWTstrategy(
17
+ {
18
+ secretOrKey: SECRET,
19
+ passReqToCallback: true,
20
+ jwtFromRequest: ExtractJwt.fromExtractors([
21
+ ExtractJwt.fromAuthHeaderAsBearerToken(),
22
+ ExtractJwt.fromHeader('authorization'),
23
+ ExtractJwt.fromHeader('x-access-token'),
24
+ ExtractJwt.fromUrlQueryParameter('access_token'),
25
+ ExtractJwt.fromBodyField('access_token'),
26
+ req => {
27
+ var token = null
28
+ token = getAccessTokenCookie(req?.ctx)
29
+ return token
30
+ }
31
+ ])
32
+ },
33
+ async (request, decoded, done) => {
34
+ try {
35
+ return done(null, decoded)
36
+ } catch (error) {
37
+ return done(error)
38
+ }
39
+ }
40
+ )
41
+ )
42
+
43
+ export async function jwtAuthenticateMiddleware(context, next) {
44
+ const { path } = context
45
+ const { user } = context.state
46
+ if (user) {
47
+ return await next()
48
+ }
49
+
50
+ return await passport.authenticate('jwt', { session: false }, async (err, decoded, info) => {
51
+ if (err || !decoded) {
52
+ const e = (context.state.error = err || info)
53
+
54
+ clearAccessTokenCookie(context)
55
+
56
+ context.throw(401, e.message)
57
+ } else {
58
+ const userEntity = await User.checkAuth(decoded)
59
+
60
+ if (userEntity.status === UserStatus.PWD_RESET_REQUIRED) {
61
+ try {
62
+ const token = makeVerificationToken()
63
+ await saveVerificationToken(userEntity.id, token, VerificationTokenType.PASSWORD_RESET)
64
+ clearAccessTokenCookie(context)
65
+ context.redirect(`/auth/reset-password?token=${token}`)
66
+ } catch (e) {
67
+ throw err
68
+ }
69
+ } else {
70
+ context.state.user = userEntity
71
+ context.state.decodedToken = decoded
72
+
73
+ if (sessionExpiryPolicy == 'rolling') {
74
+ /* To renew the expiry time on each request, a token is issued and the session is updated. */
75
+
76
+ const token = await userEntity.sign()
77
+ setAccessTokenCookie(context, token)
78
+ }
79
+
80
+ await next()
81
+ }
82
+ }
83
+ })(context, next)
84
+ }
@@ -0,0 +1,55 @@
1
+ import passport from 'koa-passport'
2
+ import { Strategy as localStrategy } from 'passport-local'
3
+
4
+ import { signin } from '../controllers/signin'
5
+
6
+ passport.use(
7
+ 'signin',
8
+ new localStrategy(
9
+ {
10
+ usernameField: 'email',
11
+ passwordField: 'password'
12
+ },
13
+ async (email, password, done) => {
14
+ try {
15
+ const {
16
+ user: userInfo,
17
+ token,
18
+ domains
19
+ } = await signin({
20
+ email,
21
+ password
22
+ })
23
+
24
+ return done(
25
+ null,
26
+ {
27
+ user: userInfo,
28
+ token,
29
+ domains
30
+ },
31
+ {
32
+ message: 'Logged in Successfully'
33
+ }
34
+ )
35
+ } catch (error) {
36
+ return done(error)
37
+ }
38
+ }
39
+ )
40
+ )
41
+
42
+ export async function signinMiddleware(context, next) {
43
+ return passport.authenticate('signin', { session: false }, async (err, user, info) => {
44
+ if (err || !user) {
45
+ throw err
46
+ } else {
47
+ const { user: userInfo, token } = user
48
+
49
+ context.state.user = userInfo
50
+ context.state.token = token
51
+
52
+ await next()
53
+ }
54
+ })(context, next)
55
+ }
@@ -0,0 +1,127 @@
1
+ import passport from 'koa-passport'
2
+ import { Strategy as CustomStrategy } from 'passport-custom'
3
+
4
+ import { getRepository } from '@things-factory/shell'
5
+
6
+ import { User } from '../service/user/user'
7
+ import { AuthError } from '../errors/auth-error'
8
+
9
+ import { WebAuthCredential } from '../service/web-auth-credential/web-auth-credential'
10
+ import { verifyRegistrationResponse, verifyAuthenticationResponse } from '@simplewebauthn/server'
11
+
12
+ import { AuthenticatorAssertionResponse } from '@simplewebauthn/types'
13
+
14
+ passport.use(
15
+ 'webauthn-register',
16
+ new CustomStrategy(async (context, done) => {
17
+ const { body, session, user, hostname, origin } = context as any
18
+
19
+ const challenge = session.challenge
20
+
21
+ const verification = await verifyRegistrationResponse({
22
+ response: body,
23
+ expectedChallenge: challenge,
24
+ expectedOrigin: origin,
25
+ expectedRPID: hostname,
26
+ expectedType: 'webauthn.create',
27
+ requireUserVerification: false
28
+ })
29
+
30
+ if (verification.verified) {
31
+ const { registrationInfo } = verification
32
+ const publicKey = Buffer.from(registrationInfo.credentialPublicKey).toString('base64')
33
+
34
+ if (user) {
35
+ const webAuthRepository = getRepository(WebAuthCredential)
36
+ await webAuthRepository.save({
37
+ user,
38
+ credentialId: registrationInfo.credentialID,
39
+ publicKey,
40
+ counter: registrationInfo.counter,
41
+ creator: user,
42
+ updater: user
43
+ })
44
+ }
45
+
46
+ return done(null, user)
47
+ } else {
48
+ return done(null, false)
49
+ }
50
+ })
51
+ )
52
+
53
+ passport.use(
54
+ 'webauthn-login',
55
+ new CustomStrategy(async (context, done) => {
56
+ try {
57
+ const { body, session, origin, hostname } = context as any
58
+
59
+ const challenge = session.challenge
60
+
61
+ const assertionResponse = body as {
62
+ id: string
63
+ response: AuthenticatorAssertionResponse
64
+ }
65
+
66
+ const credential = await getRepository(WebAuthCredential).findOne({
67
+ where: {
68
+ credentialId: assertionResponse.id
69
+ },
70
+ relations: ['user']
71
+ })
72
+
73
+ if (!credential) {
74
+ return done(null, false)
75
+ }
76
+
77
+ const verification = await verifyAuthenticationResponse({
78
+ response: body,
79
+ expectedChallenge: challenge,
80
+ expectedOrigin: origin,
81
+ expectedRPID: hostname,
82
+ requireUserVerification: false,
83
+ authenticator: {
84
+ credentialID: credential.credentialId,
85
+ credentialPublicKey: new Uint8Array(Buffer.from(credential.publicKey, 'base64')),
86
+ counter: credential.counter
87
+ }
88
+ })
89
+
90
+ if (verification.verified) {
91
+ const { authenticationInfo } = verification
92
+ credential.counter = authenticationInfo.newCounter
93
+ await getRepository(WebAuthCredential).save(credential)
94
+
95
+ const user = credential.user
96
+ return done(null, user)
97
+ } else {
98
+ return done(verification, false)
99
+ }
100
+ } catch(error) {
101
+ return done(error, false)
102
+ }
103
+ })
104
+ )
105
+
106
+ export function createWebAuthnMiddleware(strategy: 'webauthn-register' | 'webauthn-login') {
107
+ return async function webAuthnMiddleware(context, next) {
108
+ return passport.authenticate(
109
+ strategy,
110
+ { session: true, failureMessage: true, failWithError: true },
111
+ async (err, user) => {
112
+ if (err || !user) {
113
+ throw new AuthError({
114
+ errorCode: AuthError.ERROR_CODES.AUTHN_VERIFICATION_FAILED,
115
+ detail: err
116
+ })
117
+ } else {
118
+ context.state.user = user
119
+
120
+ context.body = { user, verified: true }
121
+ }
122
+
123
+ await next()
124
+ }
125
+ )(context, next)
126
+ }
127
+ }
@@ -0,0 +1,59 @@
1
+ import { ILike, MigrationInterface, QueryRunner } from 'typeorm'
2
+
3
+ import { config, logger } from '@things-factory/env'
4
+ import { Domain, getRepository } from '@things-factory/shell'
5
+
6
+ import { User, UserStatus } from '../service/user/user'
7
+
8
+ const ADMIN_ACCOUNT = config.get('adminAccount', {
9
+ name: 'Admin',
10
+ email: 'admin@hatiolab.com',
11
+ password: 'admin'
12
+ })
13
+
14
+ const SEED_USERS = [
15
+ {
16
+ ...ADMIN_ACCOUNT,
17
+ userType: 'user',
18
+ status: UserStatus.ACTIVATED
19
+ }
20
+ ]
21
+ export class SeedUsers1548206416130 implements MigrationInterface {
22
+ public async up(queryRunner: QueryRunner): Promise<any> {
23
+ const userRepository = getRepository(User)
24
+ const domainRepository = getRepository(Domain)
25
+
26
+ const domain: Domain = await domainRepository.findOne({ where: { name: 'SYSTEM' } })
27
+
28
+ try {
29
+ for (let i = 0; i < SEED_USERS.length; i++) {
30
+ const user = SEED_USERS[i]
31
+ const salt = User.generateSalt()
32
+ const password = User.encode(user.password, salt)
33
+
34
+ await userRepository.save({
35
+ ...user,
36
+ salt,
37
+ password,
38
+ domains: [domain]
39
+ })
40
+ }
41
+ } catch (e) {
42
+ logger.error(e)
43
+ }
44
+
45
+ const admin = await userRepository.findOne({ where: { email: ILike('admin@hatiolab.com') } })
46
+ domain.owner = admin.id
47
+
48
+ await domainRepository.save(domain)
49
+ }
50
+
51
+ public async down(queryRunner: QueryRunner): Promise<any> {
52
+ const repository = getRepository(User)
53
+
54
+ SEED_USERS.reverse().forEach(async user => {
55
+ let record = await repository.findOneBy({ email: ILike(user.email) })
56
+ await repository.remove(record)
57
+ })
58
+ }
59
+ }
@@ -0,0 +1,28 @@
1
+ import { MigrationInterface, QueryRunner } from 'typeorm'
2
+
3
+ import { logger } from '@things-factory/env'
4
+ import { getRepository } from '@things-factory/shell'
5
+
6
+ import { Privilege } from '../service/privilege/privilege'
7
+
8
+ export class SeedPrivilege1566805283882 implements MigrationInterface {
9
+ public async up(queryRunner: QueryRunner): Promise<any> {
10
+ const privilegeRepository = getRepository(Privilege)
11
+
12
+ const { schema } = require('@things-factory/shell/dist-server/schema')
13
+ await schema()
14
+ const privileges = process['PRIVILEGES']
15
+
16
+ try {
17
+ for (const [category, name] of Object.values(privileges as [string, string])) {
18
+ if (0 == (await privilegeRepository.count({ where: { category, name } }))) {
19
+ await privilegeRepository.save({ category, name })
20
+ }
21
+ }
22
+ } catch (e) {
23
+ logger.error(e)
24
+ }
25
+ }
26
+
27
+ public async down(queryRunner: QueryRunner): Promise<any> {}
28
+ }
@@ -0,0 +1,9 @@
1
+ const glob = require('glob')
2
+ const path = require('path')
3
+
4
+ export var migrations = []
5
+
6
+ glob.sync(path.resolve(__dirname, '.', '**', '*.js')).forEach(function(file) {
7
+ if (file.indexOf('index.js') !== -1) return
8
+ migrations = migrations.concat(Object.values(require(path.resolve(file))) || [])
9
+ })
@@ -0,0 +1,107 @@
1
+ import Router from 'koa-router'
2
+
3
+ import { config } from '@things-factory/env'
4
+ import { Domain, findSubdomainFromPath, getRedirectSubdomainPath } from '@things-factory/shell'
5
+
6
+ import { LoginHistory } from '../service/login-history/login-history'
7
+ import { User } from '../service/user/user'
8
+ import { accepts } from '../utils/accepts'
9
+ import { clearAccessTokenCookie } from '../utils/access-token-cookie'
10
+ import { getUserDomains } from '../utils/get-user-domains'
11
+
12
+ const domainType = config.get('domainType')
13
+
14
+ export const authCheckinRouter = new Router()
15
+
16
+ authCheckinRouter.get('/auth/checkin/:subdomain?', async (context, next) => {
17
+ const { request, t } = context
18
+ const header = request.header
19
+ const { user } = context.state
20
+ let { subdomain } = context.params
21
+
22
+ let domains: Partial<Domain>[] = await getUserDomains(user)
23
+ if (domainType) domains = domains.filter(d => d.extType == domainType)
24
+
25
+ if (!accepts(header.accept, ['text/html', '*/*'])) {
26
+ // When request expects non html response
27
+ try {
28
+ if (!subdomain) throw new Error(t('error.domain not specified', { subdomain })) // When params doesn't have subdomain
29
+ const checkInDomain: Partial<Domain> | undefined = domains.find(d => d.subdomain === subdomain) // When no matched domain with subdomain
30
+ if (!checkInDomain) throw new Error(t('error.domain not specified', { subdomain }))
31
+
32
+ await checkIn(checkInDomain, null, context)
33
+ context.body = true
34
+ } catch (e) {
35
+ clearAccessTokenCookie(context)
36
+ throw e
37
+ }
38
+ } else {
39
+ // When request expects html response
40
+ const { redirect_to: redirectTo = '/' } = context.query
41
+
42
+ try {
43
+ let message: string
44
+
45
+ if (!subdomain) {
46
+ /* try to find domain from redirectTo path */
47
+ subdomain = findSubdomainFromPath(context, redirectTo)
48
+ }
49
+
50
+ let checkInDomain: Partial<Domain>
51
+ if (subdomain) {
52
+ checkInDomain = domains.find(d => d.subdomain == subdomain)
53
+ if (!checkInDomain) message = t('error.domain not allowed', { subdomain })
54
+ } else if (domains.length === 1) {
55
+ checkInDomain = domains[0]
56
+ }
57
+
58
+ if (checkInDomain) {
59
+ return await checkIn(checkInDomain, redirectTo, context)
60
+ }
61
+
62
+ await context.render('auth-page', {
63
+ pageElement: 'auth-checkin',
64
+ elementScript: '/auth/checkin.js',
65
+ data: {
66
+ user: { email: user.email, locale: user.locale, name: user.name, userType: user.userType },
67
+ domains,
68
+ domainType,
69
+ redirectTo,
70
+ message
71
+ }
72
+ })
73
+ } catch (e) {
74
+ clearAccessTokenCookie(context)
75
+ context.redirect(
76
+ `/auth/signin?email=${encodeURIComponent(user.email)}&redirect_to=${encodeURIComponent(redirectTo)}`
77
+ )
78
+ }
79
+ }
80
+ })
81
+
82
+ authCheckinRouter.get('/auth/domains', async context => {
83
+ const { user } = context.state
84
+ var domains = await getUserDomains(user)
85
+ if (domainType) {
86
+ domains = domains.filter(d => d.extType == domainType)
87
+ }
88
+
89
+ context.body = domains
90
+ })
91
+
92
+ async function checkIn(
93
+ checkInDomain: Partial<Domain>,
94
+ redirectTo: string | null,
95
+ context: ResolverContext
96
+ ): Promise<void> {
97
+ const { user }: { user: User } = context.state
98
+ const remoteAddress = context.req.headers['x-forwarded-for']
99
+ ? (context.req.headers['x-forwarded-for'] as string).split(',')[0].trim()
100
+ : context.req.connection.remoteAddress
101
+
102
+ await LoginHistory.stamp(checkInDomain, user, remoteAddress)
103
+
104
+ if (redirectTo) {
105
+ return context.redirect(getRedirectSubdomainPath(context, checkInDomain.subdomain, redirectTo))
106
+ }
107
+ }
@@ -0,0 +1,107 @@
1
+ import { ILike } from 'typeorm'
2
+ import Router from 'koa-router'
3
+
4
+ import { config } from '@things-factory/env'
5
+ import { Domain, getRepository } from '@things-factory/shell'
6
+
7
+ import { changePwd } from '../controllers/change-pwd'
8
+ import { deleteUser } from '../controllers/delete-user'
9
+ import { updateProfile } from '../controllers/profile'
10
+ import { User } from '../service/user/user'
11
+ import { clearAccessTokenCookie, setAccessTokenCookie } from '../utils/access-token-cookie'
12
+ import { getUserDomains } from '../utils/get-user-domains'
13
+
14
+ const domainType = config.get('domainType')
15
+ const languages = config.get('i18n/languages') || []
16
+
17
+ export const authPrivateProcessRouter = new Router({
18
+ prefix: '/auth'
19
+ })
20
+
21
+ authPrivateProcessRouter
22
+ .post('/change-pass', async (context, next) => {
23
+ const { t } = context
24
+ let { current_pass, new_pass, confirm_pass } = context.request.body
25
+
26
+ const token = await changePwd(context.state.user, current_pass, new_pass, confirm_pass, context)
27
+
28
+ context.body = t('text.password changed successfully')
29
+
30
+ setAccessTokenCookie(context, token)
31
+ })
32
+ .post('/update-profile', async (context, next) => {
33
+ const { i18next, t } = context
34
+ const newProfiles = context.request.body
35
+ await updateProfile(context.state.user, newProfiles)
36
+
37
+ if (newProfiles.locale) {
38
+ context.body = i18next.getFixedT(newProfiles.locale)('text.profile changed successfully')
39
+ } else {
40
+ context.body = t('text.profile changed successfully')
41
+ }
42
+ })
43
+ .post('/delete-user', async (context, next) => {
44
+ const { t, session } = context
45
+ var { user } = context.state
46
+ var { email: userEmail } = user
47
+
48
+ var { password, email } = context.request.body
49
+
50
+ const userRepo = getRepository(User)
51
+ const userInfo = await userRepo.findOne({
52
+ where: {
53
+ email: ILike(userEmail)
54
+ },
55
+ relations: ['domains']
56
+ })
57
+
58
+ if (email != userEmail || !User.verify(userInfo.password, password, userInfo.salt)) {
59
+ context.status = 401
60
+ context.body = t('error.user validation failed')
61
+ return
62
+ }
63
+
64
+ await deleteUser(user)
65
+
66
+ context.body = t('text.delete account succeed')
67
+ clearAccessTokenCookie(context)
68
+ })
69
+ .get('/profile', async (context, next) => {
70
+ const { t } = context
71
+ const { domain, user, unsafeIP, prohibitedPrivileges } = context.state
72
+
73
+ if (!domain) {
74
+ context.status = 401
75
+ context.body = t('error.user validation failed')
76
+ return
77
+ }
78
+
79
+ let domains: Partial<Domain>[] = await getUserDomains(user)
80
+ domains = domains.filter((d: Domain) => d.extType == domainType)
81
+
82
+ var privileges = await User.getPrivilegesByDomain(user, domain)
83
+
84
+ if (prohibitedPrivileges) {
85
+ prohibitedPrivileges.forEach(({ category, privilege }) => {
86
+ privileges = privileges.filter(p => p.category != category || p.privilege != privilege)
87
+ })
88
+ }
89
+
90
+ context.body = {
91
+ user: {
92
+ email: user.email,
93
+ name: user.name,
94
+ userType: user.userType,
95
+ owner: await process.domainOwnerGranted(domain, user),
96
+ super: await process.superUserGranted(domain, user),
97
+ unsafeIP,
98
+ privileges
99
+ },
100
+ domains,
101
+ domain: domain && {
102
+ name: domain.name,
103
+ subdomain: domain.subdomain
104
+ },
105
+ languages
106
+ }
107
+ })