@things-factory/auth-base 8.0.0-beta.9 → 8.0.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/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,133 @@
|
|
1
|
+
import {
|
2
|
+
Column,
|
3
|
+
CreateDateColumn,
|
4
|
+
Entity,
|
5
|
+
Index,
|
6
|
+
ManyToOne,
|
7
|
+
PrimaryGeneratedColumn,
|
8
|
+
RelationId,
|
9
|
+
UpdateDateColumn
|
10
|
+
} from 'typeorm'
|
11
|
+
import { Directive, Field, ID, ObjectType } from 'type-graphql'
|
12
|
+
import { User, UserStatus } from '../user/user'
|
13
|
+
|
14
|
+
import { Domain } from '@things-factory/shell'
|
15
|
+
import { SECRET } from '../../utils/get-secret'
|
16
|
+
import { config } from '@things-factory/env'
|
17
|
+
import jwt from 'jsonwebtoken'
|
18
|
+
|
19
|
+
const ORMCONFIG = config.get('ormconfig', {})
|
20
|
+
const DATABASE_TYPE = ORMCONFIG.type
|
21
|
+
|
22
|
+
@Entity()
|
23
|
+
@Index('ix_appliance_0', (appliance: Appliance) => [appliance.domain, appliance.name], {
|
24
|
+
unique: true
|
25
|
+
})
|
26
|
+
@ObjectType()
|
27
|
+
export class Appliance {
|
28
|
+
@PrimaryGeneratedColumn('uuid')
|
29
|
+
@Field(type => ID)
|
30
|
+
readonly id: string
|
31
|
+
|
32
|
+
@ManyToOne(type => Domain)
|
33
|
+
@Field(type => Domain)
|
34
|
+
domain?: Domain
|
35
|
+
|
36
|
+
@RelationId((appliance: Appliance) => appliance.domain)
|
37
|
+
domainId: string
|
38
|
+
|
39
|
+
@Column({
|
40
|
+
nullable: true
|
41
|
+
})
|
42
|
+
@Field({ nullable: true })
|
43
|
+
serialNo: string
|
44
|
+
|
45
|
+
@Column()
|
46
|
+
@Field()
|
47
|
+
name: string
|
48
|
+
|
49
|
+
@Column()
|
50
|
+
@Field({ nullable: true })
|
51
|
+
brand: string
|
52
|
+
|
53
|
+
@Column()
|
54
|
+
@Field({ nullable: true })
|
55
|
+
model: string
|
56
|
+
|
57
|
+
@Column({
|
58
|
+
nullable: true
|
59
|
+
})
|
60
|
+
@Field({ nullable: true })
|
61
|
+
netmask: string
|
62
|
+
|
63
|
+
@Column({
|
64
|
+
nullable: true
|
65
|
+
})
|
66
|
+
@Field({ nullable: true })
|
67
|
+
description: string
|
68
|
+
|
69
|
+
@Column({
|
70
|
+
nullable: true,
|
71
|
+
type:
|
72
|
+
DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
|
73
|
+
? 'longtext'
|
74
|
+
: DATABASE_TYPE == 'oracle'
|
75
|
+
? 'clob'
|
76
|
+
: DATABASE_TYPE == 'mssql'
|
77
|
+
? 'nvarchar'
|
78
|
+
: 'varchar',
|
79
|
+
length: DATABASE_TYPE == 'mssql' ? 'MAX' : undefined
|
80
|
+
})
|
81
|
+
@Field({ nullable: true })
|
82
|
+
@Directive('@privilege(category: "security", privilege: "query", domainOwnerGranted: true)')
|
83
|
+
accessToken: string
|
84
|
+
|
85
|
+
@ManyToOne(type => User, { nullable: true })
|
86
|
+
@Field({ nullable: true })
|
87
|
+
creator: User
|
88
|
+
|
89
|
+
@RelationId((appliance: Appliance) => appliance.creator)
|
90
|
+
creatorId: string
|
91
|
+
|
92
|
+
@ManyToOne(type => User, { nullable: true })
|
93
|
+
@Field({ nullable: true })
|
94
|
+
updater: User
|
95
|
+
|
96
|
+
@RelationId((appliance: Appliance) => appliance.updater)
|
97
|
+
updaterId: string
|
98
|
+
|
99
|
+
@CreateDateColumn()
|
100
|
+
@Field({ nullable: true })
|
101
|
+
createdAt: Date
|
102
|
+
|
103
|
+
@UpdateDateColumn()
|
104
|
+
@Field({ nullable: true })
|
105
|
+
updatedAt: Date
|
106
|
+
|
107
|
+
/* signing for jsonwebtoken */
|
108
|
+
static sign(subject, expiresIn, domain, user, appliance) {
|
109
|
+
var credential = {
|
110
|
+
id: user.id,
|
111
|
+
userType: 'appliance',
|
112
|
+
appliance: {
|
113
|
+
id: appliance.id
|
114
|
+
},
|
115
|
+
status: UserStatus.ACTIVATED,
|
116
|
+
domain: {
|
117
|
+
subdomain: domain.subdomain
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
return jwt.sign(credential, SECRET, {
|
122
|
+
expiresIn,
|
123
|
+
issuer: 'hatiolab.com',
|
124
|
+
subject
|
125
|
+
})
|
126
|
+
}
|
127
|
+
|
128
|
+
static generateAccessToken(domain, user, appliance) {
|
129
|
+
/* how to set expiresIn https://github.com/vercel/ms */
|
130
|
+
let expiresIn = config.get('applianceJwtExpiresIn', '1y')
|
131
|
+
return this.sign('access-token', expiresIn, domain, user, appliance)
|
132
|
+
}
|
133
|
+
}
|
@@ -0,0 +1,104 @@
|
|
1
|
+
import { Directive, Arg, Ctx, Mutation, Resolver } from 'type-graphql'
|
2
|
+
|
3
|
+
import { getRepository } from '@things-factory/shell'
|
4
|
+
|
5
|
+
import { User } from '../user/user'
|
6
|
+
import { Application } from './application'
|
7
|
+
import { AccessToken, ApplicationPatch, NewApplication } from './application-types'
|
8
|
+
|
9
|
+
@Resolver(Application)
|
10
|
+
export class ApplicationMutation {
|
11
|
+
@Directive('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)')
|
12
|
+
@Mutation(returns => Application, { description: 'To create new application' })
|
13
|
+
async createApplication(@Arg('application') application: NewApplication, @Ctx() context: ResolverContext) {
|
14
|
+
const { domain } = context.state
|
15
|
+
return await getRepository(Application).save({
|
16
|
+
...application,
|
17
|
+
domain,
|
18
|
+
appKey: Application.generateAppKey(),
|
19
|
+
appSecret: Application.generateAppSecret(),
|
20
|
+
creator: context.state.user,
|
21
|
+
updater: context.state.user
|
22
|
+
})
|
23
|
+
}
|
24
|
+
|
25
|
+
@Directive('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)')
|
26
|
+
@Mutation(returns => Boolean, { description: 'To delete application' })
|
27
|
+
async deleteApplication(@Arg('id') id: string, @Ctx() context: ResolverContext) {
|
28
|
+
const { domain } = context.state
|
29
|
+
await getRepository(Application).delete({
|
30
|
+
domain: { id: domain.id },
|
31
|
+
id
|
32
|
+
})
|
33
|
+
return true
|
34
|
+
}
|
35
|
+
|
36
|
+
@Directive('@privilege(category: "security", privilege: "mutation", domainOwnerGranted: true)')
|
37
|
+
@Mutation(returns => Application)
|
38
|
+
async generateApplicationSecret(@Arg('id') id: string, @Ctx() context: ResolverContext) {
|
39
|
+
const { domain } = context.state
|
40
|
+
const repository = getRepository(Application)
|
41
|
+
const application = await repository.findOneBy({ domain: { id: domain.id }, id })
|
42
|
+
|
43
|
+
return await repository.save({
|
44
|
+
...application,
|
45
|
+
appSecret: Application.generateAppSecret(),
|
46
|
+
updater: context.state.user
|
47
|
+
})
|
48
|
+
}
|
49
|
+
|
50
|
+
@Directive('@privilege(category: "security", privilege: "mutation", domainOwnerGranted: true)')
|
51
|
+
@Mutation(returns => AccessToken)
|
52
|
+
async renewApplicationAccessToken(
|
53
|
+
@Arg('id') id: string,
|
54
|
+
@Ctx() context: ResolverContext,
|
55
|
+
@Arg('scope') scope?: string
|
56
|
+
) {
|
57
|
+
const { domain } = context.state
|
58
|
+
|
59
|
+
var appuser: User = await getRepository(User).findOneBy({
|
60
|
+
id,
|
61
|
+
userType: 'application'
|
62
|
+
})
|
63
|
+
|
64
|
+
if (!appuser) {
|
65
|
+
throw new Error('application is not bound')
|
66
|
+
}
|
67
|
+
|
68
|
+
const repository = getRepository(Application)
|
69
|
+
const application = await repository.findOneBy({ id: appuser.reference })
|
70
|
+
if (!application) {
|
71
|
+
throw new Error('application not found')
|
72
|
+
}
|
73
|
+
|
74
|
+
var accessToken = Application.generateAccessToken(domain, appuser, application.appSecret, scope || '')
|
75
|
+
var refreshToken = Application.generateRefreshToken(domain, appuser, application.appSecret, scope || '')
|
76
|
+
|
77
|
+
await getRepository(User).save({
|
78
|
+
...(appuser as any),
|
79
|
+
password: refreshToken
|
80
|
+
})
|
81
|
+
|
82
|
+
return {
|
83
|
+
accessToken,
|
84
|
+
refreshToken
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
@Directive('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)')
|
89
|
+
@Mutation(returns => Application)
|
90
|
+
async updateApplication(
|
91
|
+
@Arg('id') id: string,
|
92
|
+
@Arg('patch') patch: ApplicationPatch,
|
93
|
+
@Ctx() context: ResolverContext
|
94
|
+
) {
|
95
|
+
const repository = getRepository(Application)
|
96
|
+
const application = await repository.findOneBy({ id })
|
97
|
+
|
98
|
+
return await repository.save({
|
99
|
+
...application,
|
100
|
+
...patch,
|
101
|
+
updater: context.state.user
|
102
|
+
})
|
103
|
+
}
|
104
|
+
}
|
@@ -0,0 +1,98 @@
|
|
1
|
+
import { Directive, Arg, Args, Ctx, FieldResolver, Query, Resolver, Root } from 'type-graphql'
|
2
|
+
import { SelectQueryBuilder } from 'typeorm'
|
3
|
+
import { URL } from 'url'
|
4
|
+
|
5
|
+
import { config } from '@things-factory/env'
|
6
|
+
import { getQueryBuilderFromListParams, Domain, getRepository, ListParam } from '@things-factory/shell'
|
7
|
+
|
8
|
+
import { Role } from '../role/role'
|
9
|
+
import { User } from '../user/user'
|
10
|
+
import { Application } from './application'
|
11
|
+
import { ApplicationList } from './application-types'
|
12
|
+
|
13
|
+
const protocol: string = config.get('protocol')
|
14
|
+
|
15
|
+
@Resolver(Application)
|
16
|
+
export class ApplicationQuery {
|
17
|
+
@Directive('@privilege(category: "user", privilege: "query", domainOwnerGranted: true, superUserGranted: true)')
|
18
|
+
@Query(returns => Application, { description: 'To fetch application' })
|
19
|
+
async application(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Application> {
|
20
|
+
const repository = getRepository(Application)
|
21
|
+
|
22
|
+
return await repository.findOneBy({ id })
|
23
|
+
}
|
24
|
+
|
25
|
+
@Directive('@privilege(category: "user", privilege: "query", domainOwnerGranted: true, superUserGranted: true)')
|
26
|
+
@Query(returns => ApplicationList, { description: 'To fetch multiple application' })
|
27
|
+
async applications(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext) {
|
28
|
+
const { domain } = context.state
|
29
|
+
|
30
|
+
const queryBuilder = getQueryBuilderFromListParams({
|
31
|
+
domain,
|
32
|
+
params,
|
33
|
+
repository: getRepository(Application),
|
34
|
+
alias: 'application',
|
35
|
+
searchables: ['name', 'description']
|
36
|
+
})
|
37
|
+
|
38
|
+
const [items, total] = await queryBuilder.getManyAndCount()
|
39
|
+
|
40
|
+
return { items, total }
|
41
|
+
}
|
42
|
+
|
43
|
+
@FieldResolver(type => String)
|
44
|
+
async availableScopes(@Ctx() context: ResolverContext): Promise<string> {
|
45
|
+
const { domain } = context.state
|
46
|
+
const roles = await getRepository(Role).findBy({ domain: { id: domain.id } })
|
47
|
+
|
48
|
+
return roles.map((role: Role) => role.name).join(' ')
|
49
|
+
}
|
50
|
+
|
51
|
+
@FieldResolver(type => String)
|
52
|
+
async accessTokenUrl(@Ctx() context: ResolverContext): Promise<string> {
|
53
|
+
return buildAuthURL('/oauth/access-token', context)
|
54
|
+
}
|
55
|
+
|
56
|
+
@FieldResolver(type => String)
|
57
|
+
async authUrl(@Ctx() context: ResolverContext): Promise<string> {
|
58
|
+
return buildAuthURL('/oauth/authorize', context)
|
59
|
+
}
|
60
|
+
|
61
|
+
@FieldResolver(type => Domain)
|
62
|
+
async domain(@Ctx() context: ResolverContext) {
|
63
|
+
return context.state.domain
|
64
|
+
}
|
65
|
+
|
66
|
+
@FieldResolver(type => User)
|
67
|
+
async updater(@Root() application: Application): Promise<User> {
|
68
|
+
return await getRepository(User).findOneBy({ id: application.updaterId })
|
69
|
+
}
|
70
|
+
|
71
|
+
@FieldResolver(type => User)
|
72
|
+
async creator(@Root() application: Application): Promise<User> {
|
73
|
+
return await getRepository(User).findOneBy({ id: application.creatorId })
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
function buildAuthURL(pathname: string, context: ResolverContext): string {
|
78
|
+
const originalProtocol = context.headers['x-forwarded-proto']
|
79
|
+
const originalHost = context.headers['x-forwarded-host']
|
80
|
+
const originalPort = context.headers['x-forwarded-port']
|
81
|
+
|
82
|
+
if (originalProtocol && originalHost) {
|
83
|
+
var url: URL = new URL(`${originalProtocol}://${originalHost}`)
|
84
|
+
if (originalPort) {
|
85
|
+
url.port = originalPort
|
86
|
+
}
|
87
|
+
} else {
|
88
|
+
var url: URL = new URL(context.request.origin)
|
89
|
+
}
|
90
|
+
|
91
|
+
if (protocol) {
|
92
|
+
url.protocol = protocol
|
93
|
+
}
|
94
|
+
|
95
|
+
url.pathname = pathname
|
96
|
+
|
97
|
+
return url.href
|
98
|
+
}
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import { Field, InputType, Int, ObjectType } from 'type-graphql'
|
2
|
+
import { GraphQLEmailAddress } from 'graphql-scalars'
|
3
|
+
|
4
|
+
import { Application, ApplicationType } from './application'
|
5
|
+
|
6
|
+
@ObjectType()
|
7
|
+
export class AccessToken {
|
8
|
+
@Field()
|
9
|
+
accesToken: string
|
10
|
+
|
11
|
+
@Field()
|
12
|
+
refreshToken: string
|
13
|
+
}
|
14
|
+
|
15
|
+
@ObjectType()
|
16
|
+
export class ApplicationList {
|
17
|
+
@Field(type => [Application], { nullable: true })
|
18
|
+
items?: Application[]
|
19
|
+
|
20
|
+
@Field(type => Int, { nullable: true })
|
21
|
+
total?: number
|
22
|
+
}
|
23
|
+
|
24
|
+
@InputType()
|
25
|
+
export class ApplicationPatch {
|
26
|
+
@Field({ nullable: true })
|
27
|
+
name?: string
|
28
|
+
|
29
|
+
@Field({ nullable: true })
|
30
|
+
description?: string
|
31
|
+
|
32
|
+
@Field(type => GraphQLEmailAddress, { nullable: true })
|
33
|
+
email?: string
|
34
|
+
|
35
|
+
@Field({ nullable: true })
|
36
|
+
url?: string
|
37
|
+
|
38
|
+
@Field({ nullable: true })
|
39
|
+
icon?: string
|
40
|
+
|
41
|
+
@Field({ nullable: true })
|
42
|
+
redirectUrl?: string
|
43
|
+
|
44
|
+
@Field({ nullable: true })
|
45
|
+
webhook?: string
|
46
|
+
|
47
|
+
@Field(type => ApplicationType, { nullable: true })
|
48
|
+
type?: ApplicationType
|
49
|
+
}
|
50
|
+
|
51
|
+
@InputType()
|
52
|
+
export class NewApplication {
|
53
|
+
@Field()
|
54
|
+
name: string
|
55
|
+
|
56
|
+
@Field({ nullable: true })
|
57
|
+
description?: string
|
58
|
+
|
59
|
+
@Field(type => GraphQLEmailAddress, { nullable: true })
|
60
|
+
email?: string
|
61
|
+
|
62
|
+
@Field({ nullable: true })
|
63
|
+
url?: string
|
64
|
+
|
65
|
+
@Field({ nullable: true })
|
66
|
+
icon?: string
|
67
|
+
|
68
|
+
@Field({ nullable: true })
|
69
|
+
redirectUrl?: string
|
70
|
+
|
71
|
+
@Field({ nullable: true })
|
72
|
+
webhook?: string
|
73
|
+
|
74
|
+
@Field(type => ApplicationType, { nullable: true })
|
75
|
+
type?: ApplicationType
|
76
|
+
}
|
@@ -0,0 +1,216 @@
|
|
1
|
+
import crypto from 'crypto'
|
2
|
+
import jwt from 'jsonwebtoken'
|
3
|
+
import { Directive, Field, ID, ObjectType, registerEnumType } from 'type-graphql'
|
4
|
+
import { GraphQLEmailAddress } from 'graphql-scalars'
|
5
|
+
import {
|
6
|
+
Column,
|
7
|
+
CreateDateColumn,
|
8
|
+
Entity,
|
9
|
+
Index,
|
10
|
+
ManyToOne,
|
11
|
+
PrimaryGeneratedColumn,
|
12
|
+
RelationId,
|
13
|
+
UpdateDateColumn
|
14
|
+
} from 'typeorm'
|
15
|
+
|
16
|
+
import { config } from '@things-factory/env'
|
17
|
+
import { Domain } from '@things-factory/shell'
|
18
|
+
|
19
|
+
import { SECRET } from '../../utils/get-secret'
|
20
|
+
import { User, UserStatus } from '../user/user'
|
21
|
+
|
22
|
+
const ORMCONFIG = config.get('ormconfig', {})
|
23
|
+
const DATABASE_TYPE = ORMCONFIG.type
|
24
|
+
|
25
|
+
export enum ApplicationStatus {
|
26
|
+
DRAFT = 'DRAFT',
|
27
|
+
ACTIVATED = 'ACTIVATED'
|
28
|
+
}
|
29
|
+
|
30
|
+
registerEnumType(ApplicationStatus, {
|
31
|
+
name: 'ApplicationStatus',
|
32
|
+
description: 'state enumeration of a application'
|
33
|
+
})
|
34
|
+
|
35
|
+
export enum ApplicationType {
|
36
|
+
SELLERCRAFT = 'SELLERCRAFT',
|
37
|
+
XILNEX = 'XILNEX',
|
38
|
+
MMS = 'MMS',
|
39
|
+
XERO = 'XERO',
|
40
|
+
OTHERS = 'OTHERS',
|
41
|
+
SFTP = 'SFTP'
|
42
|
+
}
|
43
|
+
|
44
|
+
registerEnumType(ApplicationType, {
|
45
|
+
name: 'ApplicationType',
|
46
|
+
description: 'state enumeration of a application'
|
47
|
+
})
|
48
|
+
@Entity()
|
49
|
+
@Index('ix_application_0', (application: Application) => [application.appKey], { unique: true })
|
50
|
+
@ObjectType()
|
51
|
+
export class Application {
|
52
|
+
@PrimaryGeneratedColumn('uuid')
|
53
|
+
@Field(type => ID)
|
54
|
+
readonly id?: string
|
55
|
+
|
56
|
+
@ManyToOne(type => Domain)
|
57
|
+
@Field(type => Domain)
|
58
|
+
domain?: Domain
|
59
|
+
|
60
|
+
@RelationId((application: Application) => application.domain)
|
61
|
+
domainId?: string
|
62
|
+
|
63
|
+
@Column()
|
64
|
+
@Field()
|
65
|
+
name?: string
|
66
|
+
|
67
|
+
@Column({ nullable: true })
|
68
|
+
@Field({ nullable: true })
|
69
|
+
description?: string
|
70
|
+
|
71
|
+
@Column()
|
72
|
+
@Field(type => GraphQLEmailAddress)
|
73
|
+
email?: string
|
74
|
+
|
75
|
+
@Column()
|
76
|
+
@Field()
|
77
|
+
url?: string
|
78
|
+
|
79
|
+
@Column({ nullable: true })
|
80
|
+
@Field({ nullable: true })
|
81
|
+
icon?: string
|
82
|
+
|
83
|
+
@Column()
|
84
|
+
@Field()
|
85
|
+
redirectUrl?: string
|
86
|
+
|
87
|
+
@Column({ nullable: true })
|
88
|
+
@Field({ nullable: true })
|
89
|
+
webhook?: string
|
90
|
+
|
91
|
+
@Column({ nullable: true })
|
92
|
+
@Field({ nullable: true })
|
93
|
+
appKey?: string
|
94
|
+
|
95
|
+
@Column({
|
96
|
+
nullable: true,
|
97
|
+
type:
|
98
|
+
DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
|
99
|
+
? 'longtext'
|
100
|
+
: DATABASE_TYPE == 'oracle'
|
101
|
+
? 'clob'
|
102
|
+
: DATABASE_TYPE == 'mssql'
|
103
|
+
? 'nvarchar'
|
104
|
+
: 'varchar',
|
105
|
+
length: DATABASE_TYPE == 'mssql' ? 'MAX' : undefined
|
106
|
+
})
|
107
|
+
@Field({ nullable: true })
|
108
|
+
@Directive('@privilege(category: "security", privilege: "query", domainOwnerGranted: true)')
|
109
|
+
appSecret?: string
|
110
|
+
|
111
|
+
@Column({ default: ApplicationStatus.DRAFT })
|
112
|
+
@Field()
|
113
|
+
status?: ApplicationStatus
|
114
|
+
|
115
|
+
@Column({
|
116
|
+
type:
|
117
|
+
DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
|
118
|
+
? 'enum'
|
119
|
+
: DATABASE_TYPE == 'oracle'
|
120
|
+
? 'varchar2'
|
121
|
+
: DATABASE_TYPE == 'mssql'
|
122
|
+
? 'nvarchar'
|
123
|
+
: 'varchar',
|
124
|
+
enum:
|
125
|
+
DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
|
126
|
+
? ApplicationType
|
127
|
+
: undefined,
|
128
|
+
length: DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb' ? undefined : 32,
|
129
|
+
default: ApplicationType.OTHERS
|
130
|
+
})
|
131
|
+
@Field()
|
132
|
+
type?: ApplicationType
|
133
|
+
|
134
|
+
@CreateDateColumn()
|
135
|
+
@Field({ nullable: true })
|
136
|
+
createdAt?: Date
|
137
|
+
|
138
|
+
@UpdateDateColumn()
|
139
|
+
@Field({ nullable: true })
|
140
|
+
updatedAt?: Date
|
141
|
+
|
142
|
+
@ManyToOne(type => User, { nullable: true })
|
143
|
+
@Field(type => User, { nullable: true })
|
144
|
+
creator?: User
|
145
|
+
|
146
|
+
@RelationId((application: Application) => application.creator)
|
147
|
+
creatorId?: string
|
148
|
+
|
149
|
+
@ManyToOne(type => User, { nullable: true })
|
150
|
+
@Field(type => User, { nullable: true })
|
151
|
+
updater?: User
|
152
|
+
|
153
|
+
@RelationId((application: Application) => application.updater)
|
154
|
+
updaterId?: string
|
155
|
+
|
156
|
+
/* generateAppSecret */
|
157
|
+
static generateAppSecret() {
|
158
|
+
return crypto.randomBytes(16).toString('hex')
|
159
|
+
}
|
160
|
+
|
161
|
+
static generateAppKey() {
|
162
|
+
return crypto.randomBytes(16).toString('hex')
|
163
|
+
}
|
164
|
+
|
165
|
+
/* signing for jsonwebtoken */
|
166
|
+
static sign(subject, expiresIn, domain, user, appKey, scope) {
|
167
|
+
var application = {
|
168
|
+
id: user.id,
|
169
|
+
userType: 'application',
|
170
|
+
application: {
|
171
|
+
appKey
|
172
|
+
},
|
173
|
+
status: UserStatus.ACTIVATED,
|
174
|
+
domain: {
|
175
|
+
subdomain: domain.subdomain
|
176
|
+
},
|
177
|
+
scope
|
178
|
+
}
|
179
|
+
|
180
|
+
return jwt.sign(application, SECRET, {
|
181
|
+
expiresIn,
|
182
|
+
issuer: 'hatiolab.com',
|
183
|
+
subject
|
184
|
+
})
|
185
|
+
}
|
186
|
+
|
187
|
+
static generateAccessToken(domain, user, appKey, scope) {
|
188
|
+
/* how to set expiresIn https://github.com/vercel/ms */
|
189
|
+
return this.sign('access-token', '30d', domain, user, appKey, scope)
|
190
|
+
}
|
191
|
+
|
192
|
+
static generateRefreshToken(domain, user, appKey, scope) {
|
193
|
+
/* how to set expiresIn https://github.com/vercel/ms */
|
194
|
+
return this.sign('refresh-token', '1y', domain, user, appKey, scope)
|
195
|
+
}
|
196
|
+
|
197
|
+
/* auth-code signing for jsonwebtoken */
|
198
|
+
static generateAuthCode(email, appKey, subdomain, scopes, state) {
|
199
|
+
var credential = {
|
200
|
+
email,
|
201
|
+
appKey,
|
202
|
+
subdomain,
|
203
|
+
scopes,
|
204
|
+
state
|
205
|
+
}
|
206
|
+
|
207
|
+
return jwt.sign(credential, SECRET, {
|
208
|
+
expiresIn: '1m'
|
209
|
+
})
|
210
|
+
}
|
211
|
+
|
212
|
+
/* auth-code signing for jsonwebtoken */
|
213
|
+
static verifyAuthCode(authcode) {
|
214
|
+
return jwt.verify(authcode, SECRET)
|
215
|
+
}
|
216
|
+
}
|
@@ -0,0 +1,6 @@
|
|
1
|
+
import { Application } from './application'
|
2
|
+
import { ApplicationQuery } from './application-query'
|
3
|
+
import { ApplicationMutation } from './application-mutation'
|
4
|
+
|
5
|
+
export const entities = [Application]
|
6
|
+
export const resolvers = [ApplicationQuery, ApplicationMutation]
|