@things-factory/auth-base 8.0.0-beta.1 → 8.0.0-beta.2
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.
- package/package.json +6 -6
- package/client/actions/auth.ts +0 -24
- package/client/auth.ts +0 -272
- package/client/bootstrap.ts +0 -47
- package/client/directive/privileged.ts +0 -28
- package/client/index.ts +0 -4
- package/client/profiled.ts +0 -83
- package/client/reducers/auth.ts +0 -31
- package/client/verify-webauthn.ts +0 -86
- package/server/constants/error-code.ts +0 -22
- package/server/constants/error-message.ts +0 -0
- package/server/constants/max-age.ts +0 -1
- package/server/controllers/auth.ts +0 -5
- package/server/controllers/change-pwd.ts +0 -100
- package/server/controllers/checkin.ts +0 -21
- package/server/controllers/delete-user.ts +0 -71
- package/server/controllers/invitation.ts +0 -163
- package/server/controllers/profile.ts +0 -55
- package/server/controllers/reset-password.ts +0 -126
- package/server/controllers/signin.ts +0 -98
- package/server/controllers/signup.ts +0 -72
- package/server/controllers/unlock-user.ts +0 -62
- package/server/controllers/utils/make-invitation-token.ts +0 -5
- package/server/controllers/utils/make-verification-token.ts +0 -4
- package/server/controllers/utils/password-rule.ts +0 -120
- package/server/controllers/utils/save-invitation-token.ts +0 -10
- package/server/controllers/utils/save-verification-token.ts +0 -12
- package/server/controllers/verification.ts +0 -84
- package/server/errors/auth-error.ts +0 -24
- package/server/errors/index.ts +0 -2
- package/server/errors/user-domain-not-match-error.ts +0 -29
- package/server/index.ts +0 -37
- package/server/middlewares/authenticate-401-middleware.ts +0 -114
- package/server/middlewares/domain-authenticate-middleware.ts +0 -78
- package/server/middlewares/graphql-authenticate-middleware.ts +0 -13
- package/server/middlewares/index.ts +0 -67
- package/server/middlewares/jwt-authenticate-middleware.ts +0 -84
- package/server/middlewares/signin-middleware.ts +0 -55
- package/server/middlewares/webauthn-middleware.ts +0 -126
- package/server/migrations/1548206416130-SeedUser.ts +0 -60
- package/server/migrations/1566805283882-SeedPrivilege.ts +0 -28
- package/server/migrations/index.ts +0 -9
- package/server/router/auth-checkin-router.ts +0 -113
- package/server/router/auth-private-process-router.ts +0 -114
- package/server/router/auth-public-process-router.ts +0 -314
- package/server/router/auth-signin-router.ts +0 -55
- package/server/router/auth-signup-router.ts +0 -95
- package/server/router/index.ts +0 -9
- package/server/router/oauth2/index.ts +0 -2
- package/server/router/oauth2/oauth2-authorize-router.ts +0 -81
- package/server/router/oauth2/oauth2-router.ts +0 -165
- package/server/router/oauth2/oauth2-server.ts +0 -262
- package/server/router/oauth2/passport-oauth2-client-password.ts +0 -87
- package/server/router/oauth2/passport-refresh-token.ts +0 -87
- package/server/router/path-base-domain-router.ts +0 -8
- package/server/router/site-root-router.ts +0 -48
- package/server/router/webauthn-router.ts +0 -149
- package/server/routes.ts +0 -80
- package/server/service/app-binding/app-binding-mutation.ts +0 -22
- package/server/service/app-binding/app-binding-query.ts +0 -92
- package/server/service/app-binding/app-binding-types.ts +0 -11
- package/server/service/app-binding/app-binding.ts +0 -17
- package/server/service/app-binding/index.ts +0 -4
- package/server/service/appliance/appliance-mutation.ts +0 -113
- package/server/service/appliance/appliance-query.ts +0 -76
- package/server/service/appliance/appliance-types.ts +0 -56
- package/server/service/appliance/appliance.ts +0 -133
- package/server/service/appliance/index.ts +0 -6
- package/server/service/application/application-mutation.ts +0 -104
- package/server/service/application/application-query.ts +0 -98
- package/server/service/application/application-types.ts +0 -76
- package/server/service/application/application.ts +0 -216
- package/server/service/application/index.ts +0 -6
- package/server/service/auth-provider/auth-provider-mutation.ts +0 -159
- package/server/service/auth-provider/auth-provider-parameter-spec.ts +0 -24
- package/server/service/auth-provider/auth-provider-query.ts +0 -88
- package/server/service/auth-provider/auth-provider-type.ts +0 -67
- package/server/service/auth-provider/auth-provider.ts +0 -155
- package/server/service/auth-provider/index.ts +0 -7
- package/server/service/domain-generator/domain-generator-mutation.ts +0 -117
- package/server/service/domain-generator/domain-generator-types.ts +0 -46
- package/server/service/domain-generator/index.ts +0 -3
- package/server/service/granted-role/granted-role-mutation.ts +0 -156
- package/server/service/granted-role/granted-role-query.ts +0 -60
- package/server/service/granted-role/granted-role.ts +0 -27
- package/server/service/granted-role/index.ts +0 -6
- package/server/service/index.ts +0 -90
- package/server/service/invitation/index.ts +0 -6
- package/server/service/invitation/invitation-mutation.ts +0 -78
- package/server/service/invitation/invitation-query.ts +0 -33
- package/server/service/invitation/invitation-types.ts +0 -11
- package/server/service/invitation/invitation.ts +0 -63
- package/server/service/login-history/index.ts +0 -5
- package/server/service/login-history/login-history-query.ts +0 -51
- package/server/service/login-history/login-history-type.ts +0 -12
- package/server/service/login-history/login-history.ts +0 -45
- package/server/service/partner/index.ts +0 -6
- package/server/service/partner/partner-mutation.ts +0 -61
- package/server/service/partner/partner-query.ts +0 -102
- package/server/service/partner/partner-types.ts +0 -11
- package/server/service/partner/partner.ts +0 -57
- package/server/service/password-history/index.ts +0 -3
- package/server/service/password-history/password-history.ts +0 -16
- package/server/service/privilege/index.ts +0 -6
- package/server/service/privilege/privilege-directive.ts +0 -77
- package/server/service/privilege/privilege-mutation.ts +0 -92
- package/server/service/privilege/privilege-query.ts +0 -94
- package/server/service/privilege/privilege-types.ts +0 -60
- package/server/service/privilege/privilege.ts +0 -102
- package/server/service/role/index.ts +0 -6
- package/server/service/role/role-mutation.ts +0 -109
- package/server/service/role/role-query.ts +0 -155
- package/server/service/role/role-types.ts +0 -81
- package/server/service/role/role.ts +0 -72
- package/server/service/user/domain-query.ts +0 -24
- package/server/service/user/index.ts +0 -7
- package/server/service/user/user-mutation.ts +0 -482
- package/server/service/user/user-query.ts +0 -145
- package/server/service/user/user-types.ts +0 -100
- package/server/service/user/user.ts +0 -381
- package/server/service/users-auth-providers/index.ts +0 -5
- package/server/service/users-auth-providers/users-auth-providers.ts +0 -71
- package/server/service/verification-token/index.ts +0 -3
- package/server/service/verification-token/verification-token.ts +0 -60
- package/server/service/web-auth-credential/index.ts +0 -3
- package/server/service/web-auth-credential/web-auth-credential.ts +0 -67
- package/server/templates/account-unlock-email.ts +0 -65
- package/server/templates/invitation-email.ts +0 -66
- package/server/templates/reset-password-email.ts +0 -65
- package/server/templates/verification-email.ts +0 -66
- package/server/types.ts +0 -21
- package/server/utils/accepts.ts +0 -11
- package/server/utils/access-token-cookie.ts +0 -61
- package/server/utils/check-permission.ts +0 -52
- package/server/utils/check-user-belongs-domain.ts +0 -19
- package/server/utils/check-user-has-role.ts +0 -29
- package/server/utils/encrypt-state.ts +0 -22
- package/server/utils/get-aes-256-key.ts +0 -13
- package/server/utils/get-domain-from-hostname.ts +0 -7
- package/server/utils/get-domain-users.ts +0 -38
- package/server/utils/get-secret.ts +0 -13
- package/server/utils/get-user-domains.ts +0 -112
@@ -1,149 +0,0 @@
|
|
1
|
-
import Router from 'koa-router'
|
2
|
-
import { getRepository } from '@things-factory/shell'
|
3
|
-
import { appPackage } from '@things-factory/env'
|
4
|
-
|
5
|
-
import { generateRegistrationOptions, generateAuthenticationOptions } from '@simplewebauthn/server'
|
6
|
-
|
7
|
-
import { WebAuthCredential } from '../service/web-auth-credential/web-auth-credential'
|
8
|
-
import { PublicKeyCredentialCreationOptionsJSON } from '@simplewebauthn/server/script/deps'
|
9
|
-
import { setAccessTokenCookie } from '../utils/access-token-cookie'
|
10
|
-
import { createWebAuthnMiddleware } from '../middlewares/webauthn-middleware'
|
11
|
-
|
12
|
-
export const webAuthnGlobalPublicRouter = new Router()
|
13
|
-
export const webAuthnGlobalPrivateRouter = new Router()
|
14
|
-
|
15
|
-
const { name: rpName } = appPackage as any
|
16
|
-
|
17
|
-
// Generate authentication challenge for the currently logged-in user
|
18
|
-
webAuthnGlobalPrivateRouter.get('/auth/verify-webauthn/challenge', async (context, next) => {
|
19
|
-
const { user } = context.state
|
20
|
-
const rpID = context.hostname
|
21
|
-
|
22
|
-
if (!user) {
|
23
|
-
context.status = 401
|
24
|
-
context.body = { error: 'User not authenticated' }
|
25
|
-
return
|
26
|
-
}
|
27
|
-
|
28
|
-
const webAuthCredentials = await getRepository(WebAuthCredential).find({
|
29
|
-
where: { user: { id: user.id } }
|
30
|
-
})
|
31
|
-
|
32
|
-
if (webAuthCredentials.length === 0) {
|
33
|
-
context.status = 400
|
34
|
-
context.body = { error: 'No biometric credentials registered for this user' }
|
35
|
-
return
|
36
|
-
}
|
37
|
-
|
38
|
-
const options = await generateAuthenticationOptions({
|
39
|
-
rpID,
|
40
|
-
userVerification: 'preferred',
|
41
|
-
allowCredentials: webAuthCredentials.map(credential => ({
|
42
|
-
id: credential.credentialId,
|
43
|
-
type: 'public-key'
|
44
|
-
}))
|
45
|
-
})
|
46
|
-
|
47
|
-
context.session.challenge = options.challenge
|
48
|
-
context.body = options
|
49
|
-
})
|
50
|
-
|
51
|
-
// Verify biometric authentication
|
52
|
-
webAuthnGlobalPrivateRouter.post(
|
53
|
-
'/auth/verify-webauthn',
|
54
|
-
/* reuse webauthn-login as webauthn-verify strategy */
|
55
|
-
createWebAuthnMiddleware('webauthn-login'),
|
56
|
-
async (context, next) => {
|
57
|
-
const { user } = context.state
|
58
|
-
const { request } = context
|
59
|
-
const { body: reqBody } = request
|
60
|
-
|
61
|
-
if (!user) {
|
62
|
-
context.status = 401
|
63
|
-
context.body = { verified: false, message: 'User not authenticated' }
|
64
|
-
return
|
65
|
-
}
|
66
|
-
|
67
|
-
context.body = {
|
68
|
-
verified: true,
|
69
|
-
message: 'Biometric authentication successful'
|
70
|
-
}
|
71
|
-
|
72
|
-
await next()
|
73
|
-
}
|
74
|
-
)
|
75
|
-
|
76
|
-
// Generate registration challenge for the currently logged-in user
|
77
|
-
webAuthnGlobalPrivateRouter.get('/auth/register-webauthn/challenge', async (context, next) => {
|
78
|
-
const { user } = context.state
|
79
|
-
const rpID = context.hostname
|
80
|
-
|
81
|
-
const webAuthCredentials = await getRepository(WebAuthCredential).find({
|
82
|
-
where: {
|
83
|
-
user: { id: user.id }
|
84
|
-
}
|
85
|
-
})
|
86
|
-
|
87
|
-
const options: PublicKeyCredentialCreationOptionsJSON = await generateRegistrationOptions({
|
88
|
-
rpName,
|
89
|
-
rpID,
|
90
|
-
userName: user.email,
|
91
|
-
userDisplayName: user.name,
|
92
|
-
// Don't prompt users for additional information about the authenticator
|
93
|
-
// (Recommended for smoother UX)
|
94
|
-
attestationType: 'none',
|
95
|
-
// Prevent users from re-registering existing authenticators
|
96
|
-
excludeCredentials: webAuthCredentials.map(credential => ({
|
97
|
-
id: credential.credentialId
|
98
|
-
// Optional
|
99
|
-
// transports: credential.transports
|
100
|
-
})),
|
101
|
-
authenticatorSelection: {
|
102
|
-
// Defaults
|
103
|
-
residentKey: 'preferred',
|
104
|
-
userVerification: 'preferred',
|
105
|
-
// Optional
|
106
|
-
authenticatorAttachment: 'platform'
|
107
|
-
}
|
108
|
-
})
|
109
|
-
|
110
|
-
context.session.challenge = options.challenge
|
111
|
-
context.body = options
|
112
|
-
})
|
113
|
-
|
114
|
-
// Verify registration
|
115
|
-
webAuthnGlobalPrivateRouter.post('/auth/verify-registration', createWebAuthnMiddleware('webauthn-register'))
|
116
|
-
|
117
|
-
// Generate sign-in challenge
|
118
|
-
webAuthnGlobalPublicRouter.get('/auth/signin-webauthn/challenge', async (context, next) => {
|
119
|
-
const rpID = context.hostname
|
120
|
-
|
121
|
-
const options = await generateAuthenticationOptions({
|
122
|
-
rpID,
|
123
|
-
userVerification: 'preferred'
|
124
|
-
})
|
125
|
-
|
126
|
-
context.session.challenge = options.challenge
|
127
|
-
context.body = options
|
128
|
-
})
|
129
|
-
|
130
|
-
// Sign in with biometric authentication
|
131
|
-
webAuthnGlobalPublicRouter.post(
|
132
|
-
'/auth/signin-webauthn',
|
133
|
-
createWebAuthnMiddleware('webauthn-login'),
|
134
|
-
async (context, next) => {
|
135
|
-
const { domain, user } = context.state
|
136
|
-
const { request } = context
|
137
|
-
const { body: reqBody } = request
|
138
|
-
|
139
|
-
const token = await user.sign({ subdomain: domain?.subdomain })
|
140
|
-
setAccessTokenCookie(context, token)
|
141
|
-
|
142
|
-
var redirectURL = `/auth/checkin${domain ? '/' + domain.subdomain : ''}?redirect_to=${encodeURIComponent(reqBody.redirectTo || '/')}`
|
143
|
-
|
144
|
-
/* Due to the two-step interaction, it will be processed by fetch(...) in the browser, so it cannot be handled with a redirect(3xx) response. Therefore, respond with redirectURL as data. */
|
145
|
-
context.body = { redirectURL, verified: true }
|
146
|
-
|
147
|
-
await next()
|
148
|
-
}
|
149
|
-
)
|
package/server/routes.ts
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
import { config } from '@things-factory/env'
|
2
|
-
|
3
|
-
import { domainAuthenticateMiddleware, jwtAuthenticateMiddleware } from './middlewares'
|
4
|
-
import {
|
5
|
-
authCheckinRouter,
|
6
|
-
authPrivateProcessRouter,
|
7
|
-
authPublicProcessRouter,
|
8
|
-
authSigninRouter,
|
9
|
-
authSignupRouter,
|
10
|
-
oauth2AuthorizeRouter,
|
11
|
-
oauth2Router,
|
12
|
-
pathBaseDomainRouter,
|
13
|
-
siteRootRouter,
|
14
|
-
webAuthnGlobalPublicRouter,
|
15
|
-
webAuthnGlobalPrivateRouter
|
16
|
-
} from './router'
|
17
|
-
|
18
|
-
import { setAccessTokenCookie } from './utils/access-token-cookie'
|
19
|
-
|
20
|
-
const isPathBaseDomain = !config.get('subdomain') && !config.get('useVirtualHostBasedDomain')
|
21
|
-
|
22
|
-
process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRouter) => {
|
23
|
-
globalPublicRouter.use(siteRootRouter.routes(), siteRootRouter.allowedMethods())
|
24
|
-
globalPublicRouter.use(authPublicProcessRouter.routes(), authPublicProcessRouter.allowedMethods())
|
25
|
-
|
26
|
-
/* ssoMiddleware가 정의되어있다면, /auth/sso-signin 패스를 활성화한다. */
|
27
|
-
if (app.ssoMiddlewares.length > 0) {
|
28
|
-
authSigninRouter.get('/auth/sso-signin', app.ssoMiddlewares[0], async context => {
|
29
|
-
const { user } = context.state
|
30
|
-
|
31
|
-
const token = await user.sign()
|
32
|
-
setAccessTokenCookie(context, token)
|
33
|
-
|
34
|
-
context.redirect('/auth/checkin')
|
35
|
-
})
|
36
|
-
}
|
37
|
-
})
|
38
|
-
|
39
|
-
process.on('bootstrap-module-global-private-route' as any, (app, globalPrivateRouter) => {
|
40
|
-
globalPrivateRouter.use(jwtAuthenticateMiddleware)
|
41
|
-
|
42
|
-
/* globalPrivateRouter based nested-routers */
|
43
|
-
globalPrivateRouter.use(authCheckinRouter.routes(), authCheckinRouter.allowedMethods())
|
44
|
-
globalPrivateRouter.use(authPrivateProcessRouter.routes(), authPrivateProcessRouter.allowedMethods())
|
45
|
-
globalPrivateRouter.use(webAuthnGlobalPrivateRouter.routes(), webAuthnGlobalPrivateRouter.allowedMethods())
|
46
|
-
})
|
47
|
-
|
48
|
-
process.on('bootstrap-module-domain-public-route' as any, (app, domainPublicRouter) => {
|
49
|
-
/* domainPublicRouter based nested-routers */
|
50
|
-
domainPublicRouter.use(authSigninRouter.routes(), authSigninRouter.allowedMethods())
|
51
|
-
domainPublicRouter.use(authSignupRouter.routes(), authSignupRouter.allowedMethods())
|
52
|
-
domainPublicRouter.use(webAuthnGlobalPublicRouter.routes(), webAuthnGlobalPublicRouter.allowedMethods())
|
53
|
-
|
54
|
-
/* path '/admin/oauth/...' is deprecated. should use path '/oauth/...' for oauth2 related routing */
|
55
|
-
domainPublicRouter.use('/oauth', oauth2Router.routes(), oauth2Router.allowedMethods()) // if i use context
|
56
|
-
})
|
57
|
-
|
58
|
-
process.on('bootstrap-module-domain-private-route' as any, (app, domainPrivateRouter) => {
|
59
|
-
domainPrivateRouter.use(jwtAuthenticateMiddleware)
|
60
|
-
domainPrivateRouter.use(domainAuthenticateMiddleware)
|
61
|
-
|
62
|
-
/* domainPrivateRouter based nested-routers */
|
63
|
-
if (isPathBaseDomain) {
|
64
|
-
// pathBaseDomainRouter는 history-fallback의 경우에 인증 처리를 하기 위한 라우터이다.
|
65
|
-
// (보통, URL 링크등을 통해서 domain path URL로 바로 요청하는 경우에 해당한다.)
|
66
|
-
// pathBaseDomainRouter는 domain path를 domain-private-router를 사용하는 것을 전제로 한다.
|
67
|
-
domainPrivateRouter.use('/domain/:domain/oauth', oauth2AuthorizeRouter.routes(), oauth2AuthorizeRouter.allowedMethods())
|
68
|
-
domainPrivateRouter.use('/domain', pathBaseDomainRouter.routes(), pathBaseDomainRouter.allowedMethods())
|
69
|
-
}
|
70
|
-
|
71
|
-
// Client Routing : path 확장자가 없는 경우는 대부분 client 라우팅에 해당한다.
|
72
|
-
// 즉, browser-history-fallback 으로 index.html을 send 하는 경우에, 사용자 로그인이 필요한 경우에,
|
73
|
-
// 화면깜박임없이 signin page로 redirect 하고자하는 목적의 설정이다.
|
74
|
-
// domain-private 라우트를 통과하고 싶지 않다면, regexp를 조정한다.
|
75
|
-
// '(.[^.]+)' 은 '', '/'는 제외하고, '/xxx', '/yyy/zzz' 등 모두를 포함하지만, path에 '.'가 있는 경우는 제외한다.
|
76
|
-
// (테스트는 여기서 : http://forbeslindesay.github.io/express-route-tester/)
|
77
|
-
domainPrivateRouter.get('(.[^.]+)', async (context, next) => {
|
78
|
-
await next()
|
79
|
-
})
|
80
|
-
})
|
@@ -1,22 +0,0 @@
|
|
1
|
-
import { Arg, Ctx, Mutation, Resolver } from 'type-graphql'
|
2
|
-
|
3
|
-
import { getRepository } from '@things-factory/shell'
|
4
|
-
|
5
|
-
import { User } from '../user/user'
|
6
|
-
import { AppBinding } from './app-binding'
|
7
|
-
|
8
|
-
@Resolver(AppBinding)
|
9
|
-
export class AppBindingMutation {
|
10
|
-
@Mutation(returns => Boolean)
|
11
|
-
async deleteAppBinding(@Arg('id') id: string, @Ctx() context: ResolverContext) {
|
12
|
-
const { domain } = context.state
|
13
|
-
|
14
|
-
// TODO 이 사용자가 이 도메인에 속한 사용자인지 확인해야함.
|
15
|
-
// TODO 다른 도메인에도 포함되어있다면, domains-users 관게와 해당 도메인 관련 정보만 삭제해야 함.
|
16
|
-
await getRepository(User).delete({
|
17
|
-
id
|
18
|
-
})
|
19
|
-
|
20
|
-
return true
|
21
|
-
}
|
22
|
-
}
|
@@ -1,92 +0,0 @@
|
|
1
|
-
import { Arg, Args, Ctx, FieldResolver, Query, Resolver, Root } from 'type-graphql'
|
2
|
-
import { SelectQueryBuilder } from 'typeorm'
|
3
|
-
|
4
|
-
import { buildQuery, getRepository, ListParam } from '@things-factory/shell'
|
5
|
-
|
6
|
-
import { buildDomainUsersQueryBuilder } from '../../utils/get-domain-users'
|
7
|
-
import { Application } from '../application/application'
|
8
|
-
import { User } from '../user/user'
|
9
|
-
import { UserList } from '../user/user-types'
|
10
|
-
import { AppBinding } from './app-binding'
|
11
|
-
import { AppBindingList } from './app-binding-types'
|
12
|
-
|
13
|
-
@Resolver(AppBinding)
|
14
|
-
export class AppBindingQuery {
|
15
|
-
@Query(returns => AppBinding)
|
16
|
-
async appBinding(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<User> {
|
17
|
-
const { domain } = context.state
|
18
|
-
|
19
|
-
// TODO should check domain is available
|
20
|
-
return await getRepository(User).findOneBy({ id, userType: 'application' })
|
21
|
-
}
|
22
|
-
|
23
|
-
/* TODO optimize query */
|
24
|
-
@Query(returns => AppBindingList)
|
25
|
-
async appBindings(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<UserList> {
|
26
|
-
const { domain } = context.state
|
27
|
-
|
28
|
-
// const convertedParams = convertListParams(params)
|
29
|
-
// convertedParams.where = {
|
30
|
-
// ...convertedParams.where,
|
31
|
-
// userType: 'application'
|
32
|
-
// } as any
|
33
|
-
|
34
|
-
const alias: string = 'USER'
|
35
|
-
const qb: SelectQueryBuilder<User> = buildDomainUsersQueryBuilder(domain.id, alias)
|
36
|
-
buildQuery(qb, params, null, { domainRef: false })
|
37
|
-
var [items] = await qb
|
38
|
-
// .leftJoinAndSelect(`${alias}.roles`, 'ROLES')
|
39
|
-
// .leftJoinAndSelect(`${alias}.creator`, 'CREATOR')
|
40
|
-
// .leftJoinAndSelect(`${alias}.updater`, 'UPDATER')
|
41
|
-
.getManyAndCount()
|
42
|
-
|
43
|
-
items = items.filter((user: User) => user.userType == 'application')
|
44
|
-
|
45
|
-
// var boundApps = await Promise.all(
|
46
|
-
// items
|
47
|
-
// .filter((user: User) => user.userType == 'application')
|
48
|
-
// .map(async (user: User) => {
|
49
|
-
// const email = user.email
|
50
|
-
// const appKey = email.substr(0, email.lastIndexOf('@'))
|
51
|
-
// const application = await getRepository(Application).findOneBy({
|
52
|
-
// appKey
|
53
|
-
// })
|
54
|
-
|
55
|
-
// return {
|
56
|
-
// ...user,
|
57
|
-
// application,
|
58
|
-
// scope: user.roles.map(role => role.name).join(','),
|
59
|
-
// refreshToken: user.password
|
60
|
-
// }
|
61
|
-
// })
|
62
|
-
// )
|
63
|
-
|
64
|
-
return { items, total: items.length }
|
65
|
-
}
|
66
|
-
|
67
|
-
@FieldResolver(type => Application)
|
68
|
-
async application(@Root() appBinding: AppBinding): Promise<Application> {
|
69
|
-
return await getRepository(Application).findOneBy({ id: appBinding.reference })
|
70
|
-
}
|
71
|
-
|
72
|
-
@FieldResolver(type => String)
|
73
|
-
async scope(@Root() appBinding: AppBinding): Promise<string> {
|
74
|
-
const u = await getRepository(User).findOne({ where: { reference: appBinding.reference }, relations: ['roles'] })
|
75
|
-
return u.roles.map(role => role.name).join(',')
|
76
|
-
}
|
77
|
-
|
78
|
-
@FieldResolver(type => String)
|
79
|
-
async refreshToken(@Root() appBinding: AppBinding): Promise<string> {
|
80
|
-
return appBinding.password
|
81
|
-
}
|
82
|
-
|
83
|
-
@FieldResolver(type => User)
|
84
|
-
async updater(@Root() appBinding: AppBinding): Promise<User> {
|
85
|
-
return await getRepository(User).findOneBy({ id: appBinding.updaterId })
|
86
|
-
}
|
87
|
-
|
88
|
-
@FieldResolver(type => User)
|
89
|
-
async creator(@Root() appBinding: AppBinding): Promise<User> {
|
90
|
-
return await getRepository(User).findOneBy({ id: appBinding.creatorId })
|
91
|
-
}
|
92
|
-
}
|
@@ -1,11 +0,0 @@
|
|
1
|
-
import { Field, Int, ObjectType } from 'type-graphql'
|
2
|
-
import { AppBinding } from './app-binding'
|
3
|
-
|
4
|
-
@ObjectType()
|
5
|
-
export class AppBindingList {
|
6
|
-
@Field(type => [AppBinding], { nullable: true })
|
7
|
-
items?: [AppBinding]
|
8
|
-
|
9
|
-
@Field(type => Int, { nullable: true })
|
10
|
-
total?: number
|
11
|
-
}
|
@@ -1,17 +0,0 @@
|
|
1
|
-
import { ObjectType, Field, Directive } from 'type-graphql'
|
2
|
-
import { Domain } from '@things-factory/shell'
|
3
|
-
import { Application } from '../application/application'
|
4
|
-
import { User, UserStatus } from '../user/user'
|
5
|
-
|
6
|
-
@ObjectType()
|
7
|
-
export class AppBinding extends User {
|
8
|
-
@Field({ nullable: true })
|
9
|
-
application: Application
|
10
|
-
|
11
|
-
@Field({ nullable: true })
|
12
|
-
scope: string
|
13
|
-
|
14
|
-
@Field({ nullable: true })
|
15
|
-
@Directive('@privilege(category: "security", privilege: "query", domainOwnerGranted: true)')
|
16
|
-
refreshToken: string
|
17
|
-
}
|
@@ -1,113 +0,0 @@
|
|
1
|
-
import { Directive, Arg, Ctx, Mutation, Resolver } from 'type-graphql'
|
2
|
-
|
3
|
-
import { getRepository } from '@things-factory/shell'
|
4
|
-
|
5
|
-
import { User, UserStatus } from '../user/user'
|
6
|
-
import { Appliance } from './appliance'
|
7
|
-
import { AppliancePatch, NewAppliance } from './appliance-types'
|
8
|
-
|
9
|
-
const crypto = require('crypto')
|
10
|
-
|
11
|
-
@Resolver(Appliance)
|
12
|
-
export class ApplianceMutation {
|
13
|
-
@Directive('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)')
|
14
|
-
@Mutation(returns => Appliance, { description: 'To create new appliance' })
|
15
|
-
async createAppliance(
|
16
|
-
@Arg('appliance') appliance: NewAppliance,
|
17
|
-
@Ctx() context: ResolverContext
|
18
|
-
): Promise<Appliance> {
|
19
|
-
return await getRepository(Appliance).save({
|
20
|
-
domain: context.state.domain,
|
21
|
-
creator: context.state.user,
|
22
|
-
updater: context.state.user,
|
23
|
-
...appliance
|
24
|
-
})
|
25
|
-
}
|
26
|
-
|
27
|
-
@Directive('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)')
|
28
|
-
@Mutation(returns => Boolean, { description: 'To delete appliance' })
|
29
|
-
async deleteAppliance(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Boolean> {
|
30
|
-
const { domain } = context.state
|
31
|
-
// TODO 이 사용자가 이 도메인에 속한 사용자인지 확인해야함.
|
32
|
-
// TODO 다른 도메인에도 포함되어있다면, domains-users 관게와 해당 도메인 관련 정보만 삭제해야 함.
|
33
|
-
await getRepository(User).delete({
|
34
|
-
reference: id,
|
35
|
-
userType: 'appliance'
|
36
|
-
})
|
37
|
-
|
38
|
-
await getRepository(Appliance).delete({ domain: { id: domain.id }, id })
|
39
|
-
|
40
|
-
return true
|
41
|
-
}
|
42
|
-
|
43
|
-
@Directive('@privilege(category: "security", privilege: "mutation", domainOwnerGranted: true)')
|
44
|
-
@Mutation(returns => Appliance)
|
45
|
-
async generateApplianceSecret(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Appliance> {
|
46
|
-
const { domain, user } = context.state
|
47
|
-
|
48
|
-
const appliance: Appliance = await getRepository(Appliance).findOneBy({ domain: { id: domain.id }, id })
|
49
|
-
|
50
|
-
const appuserEmail = `${crypto.randomUUID()}@${domain?.subdomain}`
|
51
|
-
let appuser: User = await getRepository(User).findOne({
|
52
|
-
where: {
|
53
|
-
reference: id,
|
54
|
-
userType: 'appliance'
|
55
|
-
},
|
56
|
-
relations: ['domains']
|
57
|
-
})
|
58
|
-
|
59
|
-
if (!appuser) {
|
60
|
-
/* newly create appuser */
|
61
|
-
appuser = await getRepository(User).save({
|
62
|
-
email: appuserEmail,
|
63
|
-
name: appliance.name,
|
64
|
-
userType: 'appliance',
|
65
|
-
reference: id,
|
66
|
-
status: UserStatus.ACTIVATED,
|
67
|
-
domains: [domain],
|
68
|
-
updater: user,
|
69
|
-
creator: user
|
70
|
-
})
|
71
|
-
}
|
72
|
-
|
73
|
-
if (!appuser.domains.find(d => d.id === domain.id)) {
|
74
|
-
context.throw(401, 'appliance is not allowed for this domain')
|
75
|
-
}
|
76
|
-
|
77
|
-
appuser.password = Appliance.generateAccessToken(domain, appuser, appliance)
|
78
|
-
|
79
|
-
await getRepository(User).save(appuser)
|
80
|
-
|
81
|
-
return await getRepository(Appliance).save({
|
82
|
-
...appliance,
|
83
|
-
accessToken: appuser.password,
|
84
|
-
updater: user
|
85
|
-
})
|
86
|
-
}
|
87
|
-
|
88
|
-
@Directive('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)')
|
89
|
-
@Mutation(returns => Appliance)
|
90
|
-
async updateAppliance(
|
91
|
-
@Arg('id') id: string,
|
92
|
-
@Arg('patch') patch: AppliancePatch,
|
93
|
-
@Ctx() context: ResolverContext
|
94
|
-
): Promise<Appliance> {
|
95
|
-
const { domain } = context.state
|
96
|
-
|
97
|
-
const applianceRepository = getRepository(Appliance)
|
98
|
-
const userRepository = getRepository(User)
|
99
|
-
const appliance = await applianceRepository.findOne({ where: { domain: { id: domain.id }, id } })
|
100
|
-
const user = await userRepository.findOne({ where: { reference: id, userType: 'appliance' } })
|
101
|
-
|
102
|
-
userRepository.save({
|
103
|
-
...user,
|
104
|
-
name: patch?.name || user.name
|
105
|
-
})
|
106
|
-
|
107
|
-
return await applianceRepository.save({
|
108
|
-
...appliance,
|
109
|
-
...patch,
|
110
|
-
updater: context.state.user
|
111
|
-
})
|
112
|
-
}
|
113
|
-
}
|
@@ -1,76 +0,0 @@
|
|
1
|
-
import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'
|
2
|
-
|
3
|
-
import { getQueryBuilderFromListParams, Domain, getRepository, ListParam } from '@things-factory/shell'
|
4
|
-
|
5
|
-
import { Appliance } from '../appliance/appliance'
|
6
|
-
import { User } from '../user/user'
|
7
|
-
import { ApplianceList } from './appliance-types'
|
8
|
-
|
9
|
-
@Resolver(Appliance)
|
10
|
-
export class ApplianceQuery {
|
11
|
-
@Directive('@privilege(category: "user", privilege: "query", domainOwnerGranted: true, superUserGranted: true)')
|
12
|
-
@Query(returns => Appliance, { description: ' To fetch appliance' })
|
13
|
-
async appliance(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Appliance> {
|
14
|
-
const { domain } = context.state
|
15
|
-
return await getRepository(Appliance).findOneBy({ domain: { id: domain.id }, id })
|
16
|
-
}
|
17
|
-
|
18
|
-
@Directive('@privilege(category: "user", privilege: "query", domainOwnerGranted: true, superUserGranted: true)')
|
19
|
-
@Query(returns => ApplianceList, { description: 'To fetch multiple appliance' })
|
20
|
-
async appliances(
|
21
|
-
@Args(type => ListParam) params: ListParam,
|
22
|
-
@Ctx() context: ResolverContext
|
23
|
-
): Promise<ApplianceList> {
|
24
|
-
const { domain } = context.state
|
25
|
-
|
26
|
-
const queryBuilder = getQueryBuilderFromListParams({
|
27
|
-
domain,
|
28
|
-
params,
|
29
|
-
repository: getRepository(Appliance),
|
30
|
-
alias: 'appliance',
|
31
|
-
searchables: ['name', 'description']
|
32
|
-
})
|
33
|
-
|
34
|
-
const [items, total] = await queryBuilder.getManyAndCount()
|
35
|
-
|
36
|
-
return { items, total }
|
37
|
-
}
|
38
|
-
|
39
|
-
@Directive('@privilege(category: "user", privilege: "query", domainOwnerGranted: true, superUserGranted: true)')
|
40
|
-
@Query(returns => ApplianceList, { description: 'To fetch multiple appliance' })
|
41
|
-
async edges(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<ApplianceList> {
|
42
|
-
const { domain } = context.state
|
43
|
-
|
44
|
-
const queryBuilder = getQueryBuilderFromListParams({
|
45
|
-
domain,
|
46
|
-
params,
|
47
|
-
repository: getRepository(Appliance),
|
48
|
-
alias: 'appliance',
|
49
|
-
searchables: ['name', 'description']
|
50
|
-
})
|
51
|
-
|
52
|
-
const [items, total] = await queryBuilder.getManyAndCount()
|
53
|
-
|
54
|
-
return { items, total }
|
55
|
-
}
|
56
|
-
|
57
|
-
@FieldResolver(type => String)
|
58
|
-
async accessToken(@Root() appliance: Appliance, @Ctx() context: ResolverContext) {
|
59
|
-
return appliance.accessToken
|
60
|
-
}
|
61
|
-
|
62
|
-
@FieldResolver(type => Domain)
|
63
|
-
async domain(@Ctx() context: ResolverContext) {
|
64
|
-
return context.state.domain
|
65
|
-
}
|
66
|
-
|
67
|
-
@FieldResolver(type => User)
|
68
|
-
async updater(@Root() appliance: Appliance): Promise<User> {
|
69
|
-
return await getRepository(User).findOneBy({ id: appliance.updaterId })
|
70
|
-
}
|
71
|
-
|
72
|
-
@FieldResolver(type => User)
|
73
|
-
async creator(@Root() appliance: Appliance): Promise<User> {
|
74
|
-
return await getRepository(User).findOneBy({ id: appliance.creatorId })
|
75
|
-
}
|
76
|
-
}
|
@@ -1,56 +0,0 @@
|
|
1
|
-
import { ObjectType, InputType, Field, ID, Int } from 'type-graphql'
|
2
|
-
import { Appliance } from './appliance'
|
3
|
-
|
4
|
-
@ObjectType()
|
5
|
-
export class ApplianceList {
|
6
|
-
@Field(type => [Appliance], { nullable: true })
|
7
|
-
items?: Appliance[]
|
8
|
-
|
9
|
-
@Field(type => Int, { nullable: true })
|
10
|
-
total?: number
|
11
|
-
}
|
12
|
-
|
13
|
-
@InputType()
|
14
|
-
export class AppliancePatch {
|
15
|
-
@Field(type => ID, { nullable: true })
|
16
|
-
id?: string
|
17
|
-
|
18
|
-
@Field({ nullable: true })
|
19
|
-
serialNo?: string
|
20
|
-
|
21
|
-
@Field({ nullable: true })
|
22
|
-
name?: string
|
23
|
-
|
24
|
-
@Field({ nullable: true })
|
25
|
-
brand?: string
|
26
|
-
|
27
|
-
@Field({ nullable: true })
|
28
|
-
model?: string
|
29
|
-
|
30
|
-
@Field({ nullable: true })
|
31
|
-
description?: string
|
32
|
-
|
33
|
-
@Field({ nullable: true })
|
34
|
-
netmask?: string
|
35
|
-
}
|
36
|
-
|
37
|
-
@InputType()
|
38
|
-
export class NewAppliance {
|
39
|
-
@Field()
|
40
|
-
serialNo: string
|
41
|
-
|
42
|
-
@Field()
|
43
|
-
name: string
|
44
|
-
|
45
|
-
@Field()
|
46
|
-
brand: string
|
47
|
-
|
48
|
-
@Field()
|
49
|
-
model: string
|
50
|
-
|
51
|
-
@Field({ nullable: true })
|
52
|
-
description?: string
|
53
|
-
|
54
|
-
@Field({ nullable: true })
|
55
|
-
netmask?: string
|
56
|
-
}
|