@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.
- package/client/actions/auth.ts +24 -0
- package/client/auth.ts +272 -0
- package/client/bootstrap.ts +47 -0
- package/client/directive/privileged.ts +28 -0
- package/client/index.ts +3 -0
- package/client/profiled.ts +83 -0
- package/client/reducers/auth.ts +31 -0
- package/dist-client/index.d.ts +0 -1
- package/dist-client/index.js +0 -1
- package/dist-client/index.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/constants/error-code.d.ts +0 -2
- package/dist-server/constants/error-code.js +1 -3
- package/dist-server/constants/error-code.js.map +1 -1
- package/dist-server/controllers/change-pwd.js +2 -2
- package/dist-server/controllers/change-pwd.js.map +1 -1
- package/dist-server/controllers/delete-user.js +12 -13
- package/dist-server/controllers/delete-user.js.map +1 -1
- package/dist-server/controllers/invitation.d.ts +1 -2
- package/dist-server/controllers/invitation.js +5 -30
- package/dist-server/controllers/invitation.js.map +1 -1
- package/dist-server/controllers/profile.d.ts +3 -4
- package/dist-server/controllers/profile.js +2 -20
- package/dist-server/controllers/profile.js.map +1 -1
- package/dist-server/controllers/signin.d.ts +1 -4
- package/dist-server/controllers/signin.js +1 -17
- package/dist-server/controllers/signin.js.map +1 -1
- package/dist-server/controllers/signup.js +4 -13
- package/dist-server/controllers/signup.js.map +1 -1
- package/dist-server/controllers/unlock-user.js +0 -1
- package/dist-server/controllers/unlock-user.js.map +1 -1
- package/dist-server/controllers/verification.js +0 -1
- package/dist-server/controllers/verification.js.map +1 -1
- package/dist-server/middlewares/signin-middleware.js +4 -9
- package/dist-server/middlewares/signin-middleware.js.map +1 -1
- package/dist-server/middlewares/webauthn-middleware.js.map +1 -1
- package/dist-server/migrations/1548206416130-SeedUser.js +1 -2
- package/dist-server/migrations/1548206416130-SeedUser.js.map +1 -1
- package/dist-server/router/auth-checkin-router.js +2 -8
- package/dist-server/router/auth-checkin-router.js.map +1 -1
- package/dist-server/router/auth-private-process-router.js +7 -12
- package/dist-server/router/auth-private-process-router.js.map +1 -1
- package/dist-server/router/auth-public-process-router.js +9 -20
- package/dist-server/router/auth-public-process-router.js.map +1 -1
- package/dist-server/router/auth-signin-router.js +3 -3
- package/dist-server/router/auth-signin-router.js.map +1 -1
- package/dist-server/router/webauthn-router.js +1 -51
- package/dist-server/router/webauthn-router.js.map +1 -1
- package/dist-server/service/invitation/invitation-mutation.d.ts +2 -3
- package/dist-server/service/invitation/invitation-mutation.js +8 -20
- package/dist-server/service/invitation/invitation-mutation.js.map +1 -1
- package/dist-server/service/user/user-mutation.d.ts +9 -10
- package/dist-server/service/user/user-mutation.js +54 -112
- package/dist-server/service/user/user-mutation.js.map +1 -1
- package/dist-server/service/user/user-types.d.ts +0 -1
- package/dist-server/service/user/user-types.js +0 -4
- package/dist-server/service/user/user-types.js.map +1 -1
- package/dist-server/service/user/user.d.ts +0 -1
- package/dist-server/service/user/user.js +14 -40
- package/dist-server/service/user/user.js.map +1 -1
- package/dist-server/templates/account-unlock-email.d.ts +1 -2
- package/dist-server/templates/account-unlock-email.js +1 -1
- package/dist-server/templates/account-unlock-email.js.map +1 -1
- package/dist-server/templates/invitation-email.d.ts +1 -2
- package/dist-server/templates/invitation-email.js +1 -1
- package/dist-server/templates/invitation-email.js.map +1 -1
- package/dist-server/templates/verification-email.d.ts +1 -2
- package/dist-server/templates/verification-email.js +1 -1
- package/dist-server/templates/verification-email.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/server/constants/error-code.ts +20 -0
- package/server/constants/error-message.ts +0 -0
- package/server/constants/max-age.ts +1 -0
- package/server/controllers/auth.ts +5 -0
- package/server/controllers/change-pwd.ts +99 -0
- package/server/controllers/checkin.ts +21 -0
- package/server/controllers/delete-user.ts +68 -0
- package/server/controllers/invitation.ts +132 -0
- package/server/controllers/profile.ts +28 -0
- package/server/controllers/reset-password.ts +126 -0
- package/server/controllers/signin.ts +79 -0
- package/server/controllers/signup.ts +60 -0
- package/server/controllers/unlock-user.ts +61 -0
- package/server/controllers/utils/make-invitation-token.ts +5 -0
- package/server/controllers/utils/make-verification-token.ts +4 -0
- package/server/controllers/utils/password-rule.ts +120 -0
- package/server/controllers/utils/save-invitation-token.ts +10 -0
- package/server/controllers/utils/save-verification-token.ts +12 -0
- package/server/controllers/verification.ts +83 -0
- package/server/errors/auth-error.ts +24 -0
- package/server/errors/index.ts +2 -0
- package/server/errors/user-domain-not-match-error.ts +29 -0
- package/server/index.ts +37 -0
- package/server/middlewares/authenticate-401-middleware.ts +114 -0
- package/server/middlewares/domain-authenticate-middleware.ts +78 -0
- package/server/middlewares/graphql-authenticate-middleware.ts +13 -0
- package/server/middlewares/index.ts +67 -0
- package/server/middlewares/jwt-authenticate-middleware.ts +84 -0
- package/server/middlewares/signin-middleware.ts +55 -0
- package/server/middlewares/webauthn-middleware.ts +127 -0
- package/server/migrations/1548206416130-SeedUser.ts +59 -0
- package/server/migrations/1566805283882-SeedPrivilege.ts +28 -0
- package/server/migrations/index.ts +9 -0
- package/server/router/auth-checkin-router.ts +107 -0
- package/server/router/auth-private-process-router.ts +107 -0
- package/server/router/auth-public-process-router.ts +302 -0
- package/server/router/auth-signin-router.ts +55 -0
- package/server/router/auth-signup-router.ts +95 -0
- package/server/router/index.ts +9 -0
- package/server/router/oauth2/index.ts +2 -0
- package/server/router/oauth2/oauth2-authorize-router.ts +81 -0
- package/server/router/oauth2/oauth2-router.ts +165 -0
- package/server/router/oauth2/oauth2-server.ts +262 -0
- package/server/router/oauth2/passport-oauth2-client-password.ts +87 -0
- package/server/router/oauth2/passport-refresh-token.ts +87 -0
- package/server/router/path-base-domain-router.ts +8 -0
- package/server/router/site-root-router.ts +48 -0
- package/server/router/webauthn-router.ts +87 -0
- package/server/routes.ts +80 -0
- package/server/service/app-binding/app-binding-mutation.ts +22 -0
- package/server/service/app-binding/app-binding-query.ts +92 -0
- package/server/service/app-binding/app-binding-types.ts +11 -0
- package/server/service/app-binding/app-binding.ts +17 -0
- package/server/service/app-binding/index.ts +4 -0
- package/server/service/appliance/appliance-mutation.ts +113 -0
- package/server/service/appliance/appliance-query.ts +76 -0
- package/server/service/appliance/appliance-types.ts +56 -0
- package/server/service/appliance/appliance.ts +133 -0
- package/server/service/appliance/index.ts +6 -0
- package/server/service/application/application-mutation.ts +104 -0
- package/server/service/application/application-query.ts +98 -0
- package/server/service/application/application-types.ts +76 -0
- package/server/service/application/application.ts +216 -0
- package/server/service/application/index.ts +6 -0
- package/server/service/auth-provider/auth-provider-mutation.ts +159 -0
- package/server/service/auth-provider/auth-provider-parameter-spec.ts +24 -0
- package/server/service/auth-provider/auth-provider-query.ts +88 -0
- package/server/service/auth-provider/auth-provider-type.ts +67 -0
- package/server/service/auth-provider/auth-provider.ts +155 -0
- package/server/service/auth-provider/index.ts +7 -0
- package/server/service/domain-generator/domain-generator-mutation.ts +117 -0
- package/server/service/domain-generator/domain-generator-types.ts +46 -0
- package/server/service/domain-generator/index.ts +3 -0
- package/server/service/granted-role/granted-role-mutation.ts +156 -0
- package/server/service/granted-role/granted-role-query.ts +60 -0
- package/server/service/granted-role/granted-role.ts +27 -0
- package/server/service/granted-role/index.ts +6 -0
- package/server/service/index.ts +90 -0
- package/server/service/invitation/index.ts +6 -0
- package/server/service/invitation/invitation-mutation.ts +63 -0
- package/server/service/invitation/invitation-query.ts +33 -0
- package/server/service/invitation/invitation-types.ts +11 -0
- package/server/service/invitation/invitation.ts +63 -0
- package/server/service/login-history/index.ts +5 -0
- package/server/service/login-history/login-history-query.ts +51 -0
- package/server/service/login-history/login-history-type.ts +12 -0
- package/server/service/login-history/login-history.ts +45 -0
- package/server/service/partner/index.ts +6 -0
- package/server/service/partner/partner-mutation.ts +61 -0
- package/server/service/partner/partner-query.ts +102 -0
- package/server/service/partner/partner-types.ts +11 -0
- package/server/service/partner/partner.ts +57 -0
- package/server/service/password-history/index.ts +3 -0
- package/server/service/password-history/password-history.ts +16 -0
- package/server/service/privilege/index.ts +6 -0
- package/server/service/privilege/privilege-directive.ts +77 -0
- package/server/service/privilege/privilege-mutation.ts +92 -0
- package/server/service/privilege/privilege-query.ts +94 -0
- package/server/service/privilege/privilege-types.ts +60 -0
- package/server/service/privilege/privilege.ts +102 -0
- package/server/service/role/index.ts +6 -0
- package/server/service/role/role-mutation.ts +109 -0
- package/server/service/role/role-query.ts +155 -0
- package/server/service/role/role-types.ts +81 -0
- package/server/service/role/role.ts +72 -0
- package/server/service/user/domain-query.ts +24 -0
- package/server/service/user/index.ts +7 -0
- package/server/service/user/user-mutation.ts +413 -0
- package/server/service/user/user-query.ts +145 -0
- package/server/service/user/user-types.ts +97 -0
- package/server/service/user/user.ts +354 -0
- package/server/service/users-auth-providers/index.ts +5 -0
- package/server/service/users-auth-providers/users-auth-providers.ts +71 -0
- package/server/service/verification-token/index.ts +3 -0
- package/server/service/verification-token/verification-token.ts +60 -0
- package/server/service/web-auth-credential/index.ts +3 -0
- package/server/service/web-auth-credential/web-auth-credential.ts +67 -0
- package/server/templates/account-unlock-email.ts +65 -0
- package/server/templates/invitation-email.ts +66 -0
- package/server/templates/reset-password-email.ts +65 -0
- package/server/templates/verification-email.ts +66 -0
- package/server/types.ts +21 -0
- package/server/utils/accepts.ts +11 -0
- package/server/utils/access-token-cookie.ts +61 -0
- package/server/utils/check-permission.ts +52 -0
- package/server/utils/check-user-belongs-domain.ts +19 -0
- package/server/utils/check-user-has-role.ts +29 -0
- package/server/utils/encrypt-state.ts +22 -0
- package/server/utils/get-aes-256-key.ts +13 -0
- package/server/utils/get-domain-from-hostname.ts +7 -0
- package/server/utils/get-domain-users.ts +38 -0
- package/server/utils/get-secret.ts +13 -0
- package/server/utils/get-user-domains.ts +112 -0
- package/translations/en.json +1 -5
- package/translations/ja.json +1 -5
- package/translations/ko.json +3 -6
- package/translations/ms.json +1 -5
- package/translations/zh.json +1 -5
- package/dist-client/verify-webauthn.d.ts +0 -13
- package/dist-client/verify-webauthn.js +0 -72
- package/dist-client/verify-webauthn.js.map +0 -1
@@ -0,0 +1,156 @@
|
|
1
|
+
import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
|
2
|
+
import { EntityManager, In, Not, Repository } from 'typeorm'
|
3
|
+
|
4
|
+
import { Domain, getRepository } from '@things-factory/shell'
|
5
|
+
|
6
|
+
import { Partner } from '../partner/partner'
|
7
|
+
import { Role } from '../role/role'
|
8
|
+
import { RolePatch } from '../role/role-types'
|
9
|
+
import { User } from '../user/user'
|
10
|
+
import { GrantedRole } from './granted-role'
|
11
|
+
|
12
|
+
@Resolver(GrantedRole)
|
13
|
+
export class GrantedRoleMutation {
|
14
|
+
@Directive('@privilege(category: "partner", privilege: "mutation")')
|
15
|
+
@Directive('@transaction')
|
16
|
+
@Mutation(returns => Boolean)
|
17
|
+
async grantRoles(
|
18
|
+
@Arg('customerId') customerId: string,
|
19
|
+
@Arg('roles', type => [RolePatch]) roles: RolePatch[],
|
20
|
+
@Ctx() context: ResolverContext
|
21
|
+
): Promise<Boolean> {
|
22
|
+
const { tx, domain } = context.state
|
23
|
+
// Check if current domain has partnership with passed `customer`
|
24
|
+
const customerDomain: Domain = await tx.getRepository(Domain).findOneBy({ id: customerId })
|
25
|
+
const customer: Partner = await tx.getRepository(Partner).findOne({
|
26
|
+
where: { domain: { id: domain.id }, partnerDomain: { id: customerDomain.id } }
|
27
|
+
})
|
28
|
+
|
29
|
+
if (!customer) throw new Error(`Failed to find partnership with customer`)
|
30
|
+
|
31
|
+
// Remove existing granted roles
|
32
|
+
const grantedRoles: GrantedRole[] = await getGrantedRolesToCustomer(domain, customerDomain, tx)
|
33
|
+
if (grantedRoles.length) {
|
34
|
+
await tx.getRepository(GrantedRole).delete(grantedRoles.map((gr: GrantedRole) => gr.id))
|
35
|
+
}
|
36
|
+
|
37
|
+
// Insert newly granted roles
|
38
|
+
await tx.getRepository(Role).findBy({
|
39
|
+
id: In(roles.map((role: Partial<Role>) => role.id))
|
40
|
+
})
|
41
|
+
const newlyGrantedRoles: Partial<GrantedRole>[] = roles.map((role: Role) => {
|
42
|
+
return {
|
43
|
+
domain: customerDomain,
|
44
|
+
role
|
45
|
+
}
|
46
|
+
})
|
47
|
+
|
48
|
+
await tx.getRepository(GrantedRole).save(newlyGrantedRoles)
|
49
|
+
|
50
|
+
// If there's someone having role which will be removed (refuse roles)
|
51
|
+
// user roles should be removed as well
|
52
|
+
const grantedRoleIds: string[] = roles.map((role: Partial<Role>) => role.id)
|
53
|
+
const nonGrantedRoles: Role[] = await tx.getRepository(Role).find({
|
54
|
+
where: { domain: { id: domain.id }, id: Not(In(grantedRoleIds)) }
|
55
|
+
})
|
56
|
+
|
57
|
+
if (nonGrantedRoles?.length) {
|
58
|
+
// Find customer's user who has non granted roles already
|
59
|
+
const nonGrantedRoleIds: string[] = nonGrantedRoles.map((role: Role) => role.id)
|
60
|
+
|
61
|
+
let havingRefusedRoleCustomers: User[] = await getCustomerUsersByRoles(customerDomain, nonGrantedRoles, tx)
|
62
|
+
havingRefusedRoleCustomers = havingRefusedRoleCustomers.map((customerUser: User) => {
|
63
|
+
const customerDomains: Domain[] = customerUser.domains
|
64
|
+
const customerDomainIds: string[] = customerDomains.map((domain: Domain) => domain.id)
|
65
|
+
if (customerDomainIds.indexOf(domain.id) >= 0) {
|
66
|
+
// Case for customer user is a member of current domain.
|
67
|
+
// If user is a member of current domain user can have any roles of the domain even if the roles is not granted
|
68
|
+
return customerUser
|
69
|
+
} else {
|
70
|
+
// Case for customer user is an user of partner domain.
|
71
|
+
// An user of partner domain only can have granted roles
|
72
|
+
customerUser.roles = customerUser.roles.filter((role: Role) => nonGrantedRoleIds.indexOf(role.id) < 0)
|
73
|
+
return customerUser
|
74
|
+
}
|
75
|
+
})
|
76
|
+
|
77
|
+
await tx.getRepository(User).save(havingRefusedRoleCustomers)
|
78
|
+
}
|
79
|
+
return true
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
export async function getGrantedCustomerUsers(
|
84
|
+
domain: Domain,
|
85
|
+
customerDomain: Domain,
|
86
|
+
trx?: EntityManager
|
87
|
+
): Promise<User[]> {
|
88
|
+
const grantedRoles: GrantedRole[] = await getGrantedRolesToCustomer(domain, customerDomain, trx)
|
89
|
+
const roles: Role[] = grantedRoles.map((grantedRole: GrantedRole) => grantedRole.role)
|
90
|
+
return await getCustomerUsersByRoles(customerDomain, roles, trx)
|
91
|
+
}
|
92
|
+
|
93
|
+
export async function getCustomerUsersByRoles(
|
94
|
+
customerDomain: Domain,
|
95
|
+
roles: Role[],
|
96
|
+
trx?: EntityManager
|
97
|
+
): Promise<User[]> {
|
98
|
+
if (!roles.length) return []
|
99
|
+
const userRepo: Repository<User> = trx?.getRepository(User) || getRepository(User)
|
100
|
+
|
101
|
+
const customerUsers: User[] = await userRepo
|
102
|
+
.createQueryBuilder('USER')
|
103
|
+
.select('USER.id')
|
104
|
+
.distinct(true)
|
105
|
+
.leftJoin('USER.domains', 'U_DOMAIN')
|
106
|
+
.leftJoin('USER.roles', 'U_ROLE')
|
107
|
+
.where('U_DOMAIN.id = :customerDomainId', { customerDomainId: customerDomain.id })
|
108
|
+
.groupBy('USER.id')
|
109
|
+
.addGroupBy('U_ROLE.id')
|
110
|
+
.having('U_ROLE.id IN (:...roleIds)', {
|
111
|
+
roleIds: roles.map((role: Role) => role.id)
|
112
|
+
})
|
113
|
+
.getMany()
|
114
|
+
|
115
|
+
return await userRepo.find({
|
116
|
+
where: {
|
117
|
+
id: In(customerUsers.map((user: User) => user.id))
|
118
|
+
},
|
119
|
+
relations: ['domains', 'roles', 'roles.domain']
|
120
|
+
})
|
121
|
+
}
|
122
|
+
|
123
|
+
async function getGrantedRolesToCustomer(
|
124
|
+
domain: Domain,
|
125
|
+
customerDomain: Domain,
|
126
|
+
trx?: EntityManager
|
127
|
+
): Promise<GrantedRole[]> {
|
128
|
+
const grantedRoleRepo: Repository<GrantedRole> = trx?.getRepository(GrantedRole) || getRepository(GrantedRole)
|
129
|
+
const grantedRoleQueryBuilder = grantedRoleRepo.createQueryBuilder('GRANTED_ROLE')
|
130
|
+
return await grantedRoleQueryBuilder
|
131
|
+
.leftJoinAndSelect('GRANTED_ROLE.domain', 'DOMAIN')
|
132
|
+
.leftJoinAndSelect('GRANTED_ROLE.role', 'ROLE')
|
133
|
+
.leftJoin('ROLE.domain', 'R_DOMAIN')
|
134
|
+
.where('R_DOMAIN.id = :domainId', { domainId: domain.id })
|
135
|
+
.andWhere('DOMAIN.id = :customerDomainId', { customerDomainId: customerDomain.id })
|
136
|
+
.getMany()
|
137
|
+
}
|
138
|
+
|
139
|
+
export async function terminateGrantedRoles(
|
140
|
+
domain: Domain,
|
141
|
+
customerDomain: Domain,
|
142
|
+
trx?: EntityManager
|
143
|
+
): Promise<void> {
|
144
|
+
const userRepo: Repository<User> = trx?.getRepository(User) || getRepository(User)
|
145
|
+
const grantedRoleRepo: Repository<GrantedRole> = trx?.getRepository(GrantedRole) || getRepository(GrantedRole)
|
146
|
+
|
147
|
+
const grantedRoles: GrantedRole[] = await getGrantedRolesToCustomer(domain, customerDomain, trx)
|
148
|
+
const customerUsers: User[] = await getGrantedCustomerUsers(domain, customerDomain, trx)
|
149
|
+
|
150
|
+
for (let i: number = 0; i < customerUsers.length; i++) {
|
151
|
+
customerUsers[i].roles = customerUsers[i].roles.filter((role: Role) => role.domain.id !== domain.id)
|
152
|
+
}
|
153
|
+
|
154
|
+
if (customerUsers?.length) await userRepo.save(customerUsers)
|
155
|
+
if (grantedRoles?.length) await grantedRoleRepo.delete(grantedRoles.map((grantedRole: GrantedRole) => grantedRole.id))
|
156
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import { Arg, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'
|
2
|
+
import { SelectQueryBuilder } from 'typeorm'
|
3
|
+
|
4
|
+
import { Domain, getRepository } from '@things-factory/shell'
|
5
|
+
|
6
|
+
import { Partner } from '../partner/partner'
|
7
|
+
import { Role } from '../role/role'
|
8
|
+
import { GrantedRole } from './granted-role'
|
9
|
+
|
10
|
+
@Resolver(GrantedRole)
|
11
|
+
export class GrantedRoleQuery {
|
12
|
+
@Directive('@privilege(category: "user", privilege: "query", domainOwnerGranted: true, superUserGranted: true)')
|
13
|
+
@Query(returns => [GrantedRole])
|
14
|
+
async grantedRoles(@Ctx() context: ResolverContext): Promise<GrantedRole[]> {
|
15
|
+
const { domain } = context.state
|
16
|
+
return await getRepository(GrantedRole).find({
|
17
|
+
where: { domain: { id: domain.id } }
|
18
|
+
})
|
19
|
+
}
|
20
|
+
|
21
|
+
/**
|
22
|
+
* @summary The role list that target customer being granted by domain.
|
23
|
+
*
|
24
|
+
* @param customerId
|
25
|
+
* @param context
|
26
|
+
* @returns
|
27
|
+
*/
|
28
|
+
@Directive('@privilege(category: "user", privilege: "query", domainOwnerGranted: true)')
|
29
|
+
@Query(returns => [GrantedRole])
|
30
|
+
async grantingRoles(@Arg('customerId') customerId: string, @Ctx() context: ResolverContext): Promise<GrantedRole[]> {
|
31
|
+
const { domain } = context.state
|
32
|
+
const customerDomain: Domain = await getRepository(Domain).findOneBy({ id: customerId })
|
33
|
+
|
34
|
+
if (!customerDomain) throw new Error(`Failed to find customer by passed customerId (${customerId})`)
|
35
|
+
|
36
|
+
const hasPartnership: boolean = Boolean(
|
37
|
+
await getRepository(Partner).countBy({ domain: { id: domain.id }, partnerDomain: { id: customerDomain.id } })
|
38
|
+
)
|
39
|
+
|
40
|
+
if (!hasPartnership) throw new Error(`Company doesn't have partnership with ${customerDomain.name}`)
|
41
|
+
|
42
|
+
const qb: SelectQueryBuilder<GrantedRole> = getRepository(GrantedRole)
|
43
|
+
.createQueryBuilder('GRANTED_ROLE')
|
44
|
+
.leftJoin('GRANTED_ROLE.role', 'ROLE')
|
45
|
+
.where('GRANTED_ROLE.domain_id = :customerId', { customerId })
|
46
|
+
.andWhere('ROLE.domain_id = :domainId ', { domainId: domain.id })
|
47
|
+
|
48
|
+
return await qb.getMany()
|
49
|
+
}
|
50
|
+
|
51
|
+
@FieldResolver(type => Role)
|
52
|
+
async role(@Root() grantedRole: GrantedRole): Promise<Role> {
|
53
|
+
return await getRepository(Role).findOneBy({ id: grantedRole.roleId })
|
54
|
+
}
|
55
|
+
|
56
|
+
@FieldResolver(type => Domain)
|
57
|
+
async domain(@Root() grantedRole: GrantedRole): Promise<Domain> {
|
58
|
+
return await getRepository(Domain).findOneBy({ id: grantedRole.domainId })
|
59
|
+
}
|
60
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { Domain } from '@things-factory/shell'
|
2
|
+
import { Role } from '../role/role'
|
3
|
+
import { ObjectType, Field, ID } from 'type-graphql'
|
4
|
+
import { Entity, ManyToOne, PrimaryGeneratedColumn, Index, RelationId } from 'typeorm'
|
5
|
+
|
6
|
+
@Entity()
|
7
|
+
@Index('ix_granted_role_0', (grantedRole: GrantedRole) => [grantedRole.role, grantedRole.domain], { unique: true })
|
8
|
+
@ObjectType()
|
9
|
+
export class GrantedRole {
|
10
|
+
@PrimaryGeneratedColumn('uuid')
|
11
|
+
@Field(type => ID)
|
12
|
+
readonly id: string
|
13
|
+
|
14
|
+
@ManyToOne(type => Role)
|
15
|
+
@Field()
|
16
|
+
role: Role
|
17
|
+
|
18
|
+
@RelationId((grantedRole: GrantedRole) => grantedRole.role)
|
19
|
+
roleId: string
|
20
|
+
|
21
|
+
@ManyToOne(type => Domain)
|
22
|
+
@Field(type => Domain)
|
23
|
+
domain?: Domain
|
24
|
+
|
25
|
+
@RelationId((grantedRole: GrantedRole) => grantedRole.domain)
|
26
|
+
domainId: string
|
27
|
+
}
|
@@ -0,0 +1,6 @@
|
|
1
|
+
import { GrantedRole } from './granted-role'
|
2
|
+
import { GrantedRoleQuery } from './granted-role-query'
|
3
|
+
import { GrantedRoleMutation } from './granted-role-mutation'
|
4
|
+
|
5
|
+
export const entities = [GrantedRole]
|
6
|
+
export const resolvers = [GrantedRoleQuery, GrantedRoleMutation]
|
@@ -0,0 +1,90 @@
|
|
1
|
+
/* IMPORT ENTITIES AND RESOLVERS */
|
2
|
+
import { entities as UsersAuthProvidersEntities, resolvers as UsersAuthProvidersResolvers } from './users-auth-providers'
|
3
|
+
import { entities as AuthProviderEntities, resolvers as AuthProviderResolvers } from './auth-provider'
|
4
|
+
import { resolvers as AppbindingResolver } from './app-binding'
|
5
|
+
import { entities as ApplianceEntities, resolvers as ApplianceResolvers } from './appliance'
|
6
|
+
import { entities as ApplicationEntities, resolvers as ApplicationResolvers } from './application'
|
7
|
+
import { resolvers as DomainGeneratorResolver } from './domain-generator'
|
8
|
+
import { entities as GrantedRoleEntities, resolvers as GrantedRoleResolver } from './granted-role'
|
9
|
+
import { entities as InvitationEntities, resolvers as InvitationResolver } from './invitation'
|
10
|
+
import { entities as LoginHistoryEntities, resolvers as LoginHistoryResolver } from './login-history'
|
11
|
+
import { entities as PartnerEntities, resolvers as PartnerResolvers } from './partner'
|
12
|
+
import { entities as PasswordHistoryEntities } from './password-history'
|
13
|
+
import { entities as PrivilegeEntities, resolvers as PrivilegeResolvers } from './privilege'
|
14
|
+
import { privilegeDirectiveResolver, privilegeDirectiveTypeDefs } from './privilege/privilege-directive'
|
15
|
+
import { entities as RoleEntities, resolvers as RoleResolvers } from './role'
|
16
|
+
import { entities as UserEntities, resolvers as UserResolvers } from './user'
|
17
|
+
import { entities as VerificationTokenEntities } from './verification-token'
|
18
|
+
import { entities as WebAuthCredentialEntities } from './web-auth-credential'
|
19
|
+
|
20
|
+
/* EXPORT ENTITY TYPES */
|
21
|
+
export * from './users-auth-providers/users-auth-providers'
|
22
|
+
export * from './auth-provider/auth-provider'
|
23
|
+
export * from './application/application'
|
24
|
+
export * from './appliance/appliance'
|
25
|
+
export * from './privilege/privilege'
|
26
|
+
export * from './role/role'
|
27
|
+
export * from './user/user'
|
28
|
+
export * from './partner/partner'
|
29
|
+
export * from './granted-role/granted-role'
|
30
|
+
export * from './invitation/invitation'
|
31
|
+
export * from './app-binding/app-binding'
|
32
|
+
export * from './password-history/password-history'
|
33
|
+
export * from './verification-token/verification-token'
|
34
|
+
export * from './login-history/login-history'
|
35
|
+
export * from './web-auth-credential/web-auth-credential'
|
36
|
+
|
37
|
+
/* EXPORT TYPES */
|
38
|
+
export * from './app-binding/app-binding-types'
|
39
|
+
export * from './appliance/appliance-types'
|
40
|
+
export * from './application/application-types'
|
41
|
+
export * from './domain-generator/domain-generator-types'
|
42
|
+
export * from './invitation/invitation-types'
|
43
|
+
export * from './partner/partner-types'
|
44
|
+
export * from './privilege/privilege-types'
|
45
|
+
export * from './role/role-types'
|
46
|
+
export * from './user/user-types'
|
47
|
+
|
48
|
+
export const entities = [
|
49
|
+
/* ENTITIES */
|
50
|
+
...UsersAuthProvidersEntities,
|
51
|
+
...AuthProviderEntities,
|
52
|
+
...ApplicationEntities,
|
53
|
+
...ApplianceEntities,
|
54
|
+
...PrivilegeEntities,
|
55
|
+
...RoleEntities,
|
56
|
+
...UserEntities,
|
57
|
+
...PartnerEntities,
|
58
|
+
...GrantedRoleEntities,
|
59
|
+
...InvitationEntities,
|
60
|
+
...PasswordHistoryEntities,
|
61
|
+
...VerificationTokenEntities,
|
62
|
+
...LoginHistoryEntities,
|
63
|
+
...WebAuthCredentialEntities
|
64
|
+
]
|
65
|
+
|
66
|
+
export const schema = {
|
67
|
+
typeDefs: {
|
68
|
+
privilegeDirectiveTypeDefs
|
69
|
+
},
|
70
|
+
|
71
|
+
resolverClasses: [
|
72
|
+
/* RESOLVER CLASSES */
|
73
|
+
...UsersAuthProvidersResolvers,
|
74
|
+
...AuthProviderResolvers,
|
75
|
+
...ApplicationResolvers,
|
76
|
+
...ApplianceResolvers,
|
77
|
+
...PrivilegeResolvers,
|
78
|
+
...RoleResolvers,
|
79
|
+
...UserResolvers,
|
80
|
+
...PartnerResolvers,
|
81
|
+
...GrantedRoleResolver,
|
82
|
+
...InvitationResolver,
|
83
|
+
...AppbindingResolver,
|
84
|
+
...DomainGeneratorResolver,
|
85
|
+
...LoginHistoryResolver
|
86
|
+
],
|
87
|
+
directives: {
|
88
|
+
privilege: privilegeDirectiveResolver
|
89
|
+
}
|
90
|
+
}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
import { Arg, Ctx, Mutation, Resolver } from 'type-graphql'
|
2
|
+
import { GraphQLEmailAddress } from 'graphql-scalars'
|
3
|
+
|
4
|
+
import { getRepository } from '@things-factory/shell'
|
5
|
+
|
6
|
+
import { sendInvitationEmail } from '../../controllers/invitation'
|
7
|
+
import { Invitation } from './invitation'
|
8
|
+
|
9
|
+
@Resolver(Invitation)
|
10
|
+
export class InvitationMutation {
|
11
|
+
@Mutation(returns => Boolean)
|
12
|
+
async cancelInvitation(
|
13
|
+
@Arg('email', type => GraphQLEmailAddress) email: string,
|
14
|
+
@Arg('reference') reference: string,
|
15
|
+
@Arg('type') type: string
|
16
|
+
) {
|
17
|
+
const repository = getRepository(Invitation)
|
18
|
+
|
19
|
+
await repository.delete({
|
20
|
+
email,
|
21
|
+
reference,
|
22
|
+
type
|
23
|
+
})
|
24
|
+
|
25
|
+
return true
|
26
|
+
}
|
27
|
+
|
28
|
+
@Mutation(returns => Invitation)
|
29
|
+
async sendInvitation(
|
30
|
+
@Arg('email', type => GraphQLEmailAddress) email: string,
|
31
|
+
@Arg('reference') reference: string,
|
32
|
+
@Arg('type') type: string,
|
33
|
+
@Ctx() context: ResolverContext
|
34
|
+
) {
|
35
|
+
const repository = getRepository(Invitation)
|
36
|
+
|
37
|
+
const oldone = await repository.findOneBy({
|
38
|
+
email,
|
39
|
+
type,
|
40
|
+
reference
|
41
|
+
})
|
42
|
+
|
43
|
+
// TODO send invitation
|
44
|
+
await sendInvitationEmail({
|
45
|
+
invitation: {
|
46
|
+
email,
|
47
|
+
reference,
|
48
|
+
type
|
49
|
+
},
|
50
|
+
context
|
51
|
+
})
|
52
|
+
|
53
|
+
// update or create
|
54
|
+
return await repository.save({
|
55
|
+
...oldone, // take only id from oldone for update
|
56
|
+
email,
|
57
|
+
reference,
|
58
|
+
type,
|
59
|
+
creator: context.state.user,
|
60
|
+
updater: context.state.user
|
61
|
+
})
|
62
|
+
}
|
63
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import { GraphQLEmailAddress } from 'graphql-scalars'
|
2
|
+
import { Arg, Query, Resolver } from 'type-graphql'
|
3
|
+
|
4
|
+
import { getRepository } from '@things-factory/shell'
|
5
|
+
|
6
|
+
import { Invitation } from './invitation'
|
7
|
+
import { InvitationList } from './invitation-types'
|
8
|
+
|
9
|
+
@Resolver(Invitation)
|
10
|
+
export class InvitationQuery {
|
11
|
+
@Query(returns => Invitation)
|
12
|
+
async invitation(
|
13
|
+
@Arg('email', type => GraphQLEmailAddress) email: string,
|
14
|
+
@Arg('reference') reference: string,
|
15
|
+
@Arg('type') type: string
|
16
|
+
) {
|
17
|
+
return await getRepository(Invitation).findOneBy({
|
18
|
+
email,
|
19
|
+
reference,
|
20
|
+
type
|
21
|
+
})
|
22
|
+
}
|
23
|
+
|
24
|
+
@Query(returns => InvitationList)
|
25
|
+
async invitations(@Arg('reference') reference: string, @Arg('type') type: string) {
|
26
|
+
const [items, total] = await getRepository(Invitation).findAndCountBy({
|
27
|
+
reference,
|
28
|
+
type
|
29
|
+
})
|
30
|
+
|
31
|
+
return { items, total }
|
32
|
+
}
|
33
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { Invitation } from './invitation'
|
2
|
+
import { ObjectType, Field, Int } from 'type-graphql'
|
3
|
+
|
4
|
+
@ObjectType()
|
5
|
+
export class InvitationList {
|
6
|
+
@Field(type => [Invitation], { nullable: true })
|
7
|
+
items: Invitation[]
|
8
|
+
|
9
|
+
@Field(type => Int, { nullable: true })
|
10
|
+
total: number
|
11
|
+
}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
import {
|
2
|
+
CreateDateColumn,
|
3
|
+
UpdateDateColumn,
|
4
|
+
Entity,
|
5
|
+
Index,
|
6
|
+
Column,
|
7
|
+
ManyToOne,
|
8
|
+
RelationId,
|
9
|
+
PrimaryGeneratedColumn
|
10
|
+
} from 'typeorm'
|
11
|
+
import { ObjectType, Field, ID } from 'type-graphql'
|
12
|
+
import { GraphQLEmailAddress } from 'graphql-scalars'
|
13
|
+
import { User } from '../user/user'
|
14
|
+
|
15
|
+
@Entity()
|
16
|
+
@Index('ix_invitation_0', (invitation: Invitation) => [invitation.email, invitation.reference, invitation.type], {
|
17
|
+
unique: true
|
18
|
+
})
|
19
|
+
@Index('ix_invitation_1', (invitation: Invitation) => [invitation.token], { unique: true })
|
20
|
+
@ObjectType()
|
21
|
+
export class Invitation {
|
22
|
+
@PrimaryGeneratedColumn('uuid')
|
23
|
+
@Field(type => ID)
|
24
|
+
readonly id: string
|
25
|
+
|
26
|
+
@Column()
|
27
|
+
@Field(type => GraphQLEmailAddress)
|
28
|
+
email: string
|
29
|
+
|
30
|
+
@Column()
|
31
|
+
@Field()
|
32
|
+
reference: string // company, bizplace
|
33
|
+
|
34
|
+
@Column()
|
35
|
+
@Field()
|
36
|
+
type: string // company, bizplace, .. should think whether this column needs.
|
37
|
+
|
38
|
+
@Column()
|
39
|
+
@Field()
|
40
|
+
token: string
|
41
|
+
|
42
|
+
@CreateDateColumn({ nullable: true })
|
43
|
+
@Field({ nullable: true })
|
44
|
+
createdAt: Date
|
45
|
+
|
46
|
+
@UpdateDateColumn({ nullable: true })
|
47
|
+
@Field({ nullable: true })
|
48
|
+
updatedAt: Date
|
49
|
+
|
50
|
+
@ManyToOne(type => User, { nullable: true })
|
51
|
+
@Field({ nullable: true })
|
52
|
+
creator: User
|
53
|
+
|
54
|
+
@RelationId((invitation: Invitation) => invitation.creator)
|
55
|
+
creatorId: string
|
56
|
+
|
57
|
+
@ManyToOne(type => User, { nullable: true })
|
58
|
+
@Field({ nullable: true })
|
59
|
+
updater: User
|
60
|
+
|
61
|
+
@RelationId((invitation: Invitation) => invitation.updater)
|
62
|
+
updaterId: string
|
63
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
import { Arg, Args, Ctx, FieldResolver, Query, Resolver, Root } from 'type-graphql'
|
2
|
+
|
3
|
+
import { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'
|
4
|
+
|
5
|
+
import { User } from '../user/user'
|
6
|
+
import { LoginHistory } from './login-history'
|
7
|
+
import { LoginHistoryList } from './login-history-type'
|
8
|
+
|
9
|
+
@Resolver(LoginHistory)
|
10
|
+
export class LoginHistoryQuery {
|
11
|
+
@Query(returns => LoginHistoryList, { description: 'To fetch multiple LoginHistories' })
|
12
|
+
async loginHistories(
|
13
|
+
@Args(type => ListParam) params: ListParam,
|
14
|
+
@Ctx() context: ResolverContext
|
15
|
+
): Promise<LoginHistoryList> {
|
16
|
+
const { domain } = context.state
|
17
|
+
|
18
|
+
const queryBuilder = getQueryBuilderFromListParams({
|
19
|
+
domain,
|
20
|
+
params,
|
21
|
+
repository: await getRepository(LoginHistory)
|
22
|
+
})
|
23
|
+
|
24
|
+
const [items, total] = await queryBuilder.getManyAndCount()
|
25
|
+
return { items, total }
|
26
|
+
}
|
27
|
+
|
28
|
+
@Query(returns => [LoginHistory])
|
29
|
+
async myLoginHistories(@Arg('limit') limit: number, @Ctx() context: ResolverContext): Promise<LoginHistory[]> {
|
30
|
+
const user: User = context.state.user
|
31
|
+
if (!user) {
|
32
|
+
throw new Error('No user specified')
|
33
|
+
}
|
34
|
+
|
35
|
+
return await getRepository(LoginHistory).find({
|
36
|
+
where: { accessUser: { id: user.id } },
|
37
|
+
take: limit || 10,
|
38
|
+
order: { accessedAt: 'DESC' }
|
39
|
+
})
|
40
|
+
}
|
41
|
+
|
42
|
+
@FieldResolver()
|
43
|
+
async accessDomain(@Root() loginHistory: LoginHistory) {
|
44
|
+
return await getRepository(Domain).findOneBy({ id: loginHistory.accessDomainId })
|
45
|
+
}
|
46
|
+
|
47
|
+
@FieldResolver()
|
48
|
+
async accessUser(@Root() loginHistory: LoginHistory) {
|
49
|
+
return await getRepository(User).findOneBy({ id: loginHistory.accessUserId })
|
50
|
+
}
|
51
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { Field, ID, InputType, Int, ObjectType } from 'type-graphql'
|
2
|
+
|
3
|
+
import { LoginHistory } from './login-history'
|
4
|
+
|
5
|
+
@ObjectType()
|
6
|
+
export class LoginHistoryList {
|
7
|
+
@Field(type => [LoginHistory])
|
8
|
+
items: LoginHistory[]
|
9
|
+
|
10
|
+
@Field(type => Int)
|
11
|
+
total: number
|
12
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import { Field, ID, ObjectType } from 'type-graphql'
|
2
|
+
import { Column, CreateDateColumn, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId } from 'typeorm'
|
3
|
+
|
4
|
+
import { Domain, getRepository } from '@things-factory/shell'
|
5
|
+
|
6
|
+
import { User } from '../user/user'
|
7
|
+
|
8
|
+
@Entity()
|
9
|
+
@Index('ix_login_history_0', (loginHistory: LoginHistory) => [loginHistory.accessDomain, loginHistory.accessUser])
|
10
|
+
@ObjectType()
|
11
|
+
export class LoginHistory {
|
12
|
+
@PrimaryGeneratedColumn('uuid')
|
13
|
+
@Field(type => ID)
|
14
|
+
readonly id: string
|
15
|
+
|
16
|
+
@ManyToOne(type => Domain)
|
17
|
+
@Field(type => Domain)
|
18
|
+
accessDomain?: Domain
|
19
|
+
|
20
|
+
@RelationId((loginHistory: LoginHistory) => loginHistory.accessDomain)
|
21
|
+
accessDomainId: string
|
22
|
+
|
23
|
+
@ManyToOne(type => User)
|
24
|
+
@Field(type => User)
|
25
|
+
accessUser: User
|
26
|
+
|
27
|
+
@RelationId((loginHistory: LoginHistory) => loginHistory.accessUser)
|
28
|
+
accessUserId: string
|
29
|
+
|
30
|
+
@Column({ nullable: true })
|
31
|
+
@Field({ nullable: true })
|
32
|
+
accessorIp: string
|
33
|
+
|
34
|
+
@CreateDateColumn()
|
35
|
+
@Field({ nullable: true })
|
36
|
+
accessedAt: Date
|
37
|
+
|
38
|
+
static async stamp(accessDomain: Partial<Domain>, accessUser: User, accessorIp: string): Promise<void> {
|
39
|
+
await getRepository(LoginHistory).save({
|
40
|
+
accessDomain,
|
41
|
+
accessUser,
|
42
|
+
accessorIp
|
43
|
+
})
|
44
|
+
}
|
45
|
+
}
|