]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/models/oauth/oauth-token.ts
Refactor auth flow
[github/Chocobozzz/PeerTube.git] / server / models / oauth / oauth-token.ts
CommitLineData
b49f22d8 1import { Transaction } from 'sequelize'
f201a749 2import {
d175a6f7 3 AfterDestroy,
f201a749
C
4 AfterUpdate,
5 AllowNull,
6 BelongsTo,
7 Column,
8 CreatedAt,
9 ForeignKey,
10 Model,
11 Scopes,
12 Table,
13 UpdatedAt
14} from 'sequelize-typescript'
f43db2f4
C
15import { TokensCache } from '@server/lib/auth/tokens-cache'
16import { MUserAccountId } from '@server/types/models'
b49f22d8 17import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token'
da854ddd 18import { logger } from '../../helpers/logger'
91411dba 19import { AccountModel } from '../account/account'
b49f22d8 20import { UserModel } from '../account/user'
91411dba 21import { ActorModel } from '../activitypub/actor'
b49f22d8 22import { OAuthClientModel } from './oauth-client'
3fd3ab2d
C
23
24export type OAuthTokenInfo = {
25 refreshToken: string
a1587156 26 refreshTokenExpiresAt: Date
3fd3ab2d
C
27 client: {
28 id: number
a1587156 29 }
f43db2f4 30 user: MUserAccountId
e307e4fc 31 token: MOAuthTokenUser
3fd3ab2d 32}
2f372a86 33
d48ff09d 34enum ScopeNames {
91411dba 35 WITH_USER = 'WITH_USER'
d48ff09d
C
36}
37
3acc5084 38@Scopes(() => ({
91411dba 39 [ScopeNames.WITH_USER]: {
d48ff09d
C
40 include: [
41 {
3acc5084 42 model: UserModel.unscoped(),
91411dba 43 required: true,
d48ff09d
C
44 include: [
45 {
91411dba 46 attributes: [ 'id' ],
3acc5084 47 model: AccountModel.unscoped(),
91411dba
C
48 required: true,
49 include: [
50 {
5c6d985f 51 attributes: [ 'id', 'url' ],
3acc5084 52 model: ActorModel.unscoped(),
91411dba
C
53 required: true
54 }
55 ]
d48ff09d
C
56 }
57 ]
58 }
3acc5084 59 ]
d48ff09d 60 }
3acc5084 61}))
3fd3ab2d
C
62@Table({
63 tableName: 'oAuthToken',
64 indexes: [
feb4bdfd 65 {
3fd3ab2d
C
66 fields: [ 'refreshToken' ],
67 unique: true
feb4bdfd
C
68 },
69 {
3fd3ab2d
C
70 fields: [ 'accessToken' ],
71 unique: true
72 },
73 {
74 fields: [ 'userId' ]
75 },
76 {
77 fields: [ 'oAuthClientId' ]
feb4bdfd 78 }
3fd3ab2d
C
79 ]
80})
b49f22d8 81export class OAuthTokenModel extends Model {
feb4bdfd 82
3fd3ab2d
C
83 @AllowNull(false)
84 @Column
85 accessToken: string
e02643f3 86
3fd3ab2d
C
87 @AllowNull(false)
88 @Column
89 accessTokenExpiresAt: Date
e02643f3 90
3fd3ab2d
C
91 @AllowNull(false)
92 @Column
93 refreshToken: string
69b0a27c 94
3fd3ab2d
C
95 @AllowNull(false)
96 @Column
97 refreshTokenExpiresAt: Date
69b0a27c 98
e1c55031
C
99 @Column
100 authName: string
101
3fd3ab2d
C
102 @CreatedAt
103 createdAt: Date
104
105 @UpdatedAt
106 updatedAt: Date
107
108 @ForeignKey(() => UserModel)
109 @Column
110 userId: number
111
112 @BelongsTo(() => UserModel, {
feb4bdfd 113 foreignKey: {
feb4bdfd
C
114 allowNull: false
115 },
116 onDelete: 'cascade'
117 })
3fd3ab2d 118 User: UserModel
319d072e 119
3fd3ab2d
C
120 @ForeignKey(() => OAuthClientModel)
121 @Column
122 oAuthClientId: number
123
124 @BelongsTo(() => OAuthClientModel, {
319d072e 125 foreignKey: {
319d072e
C
126 allowNull: false
127 },
128 onDelete: 'cascade'
129 })
3fd3ab2d 130 OAuthClients: OAuthClientModel[]
feb4bdfd 131
f201a749 132 @AfterUpdate
d175a6f7 133 @AfterDestroy
f201a749 134 static removeTokenCache (token: OAuthTokenModel) {
f43db2f4 135 return TokensCache.Instance.clearCacheByToken(token.accessToken)
f201a749
C
136 }
137
e307e4fc
C
138 static loadByRefreshToken (refreshToken: string) {
139 const query = {
140 where: { refreshToken }
141 }
142
143 return OAuthTokenModel.findOne(query)
144 }
145
3fd3ab2d
C
146 static getByRefreshTokenAndPopulateClient (refreshToken: string) {
147 const query = {
148 where: {
e307e4fc 149 refreshToken
3fd3ab2d
C
150 },
151 include: [ OAuthClientModel ]
152 }
153
e307e4fc
C
154 return OAuthTokenModel.scope(ScopeNames.WITH_USER)
155 .findOne(query)
156 .then(token => {
157 if (!token) return null
158
159 return {
160 refreshToken: token.refreshToken,
161 refreshTokenExpiresAt: token.refreshTokenExpiresAt,
162 client: {
163 id: token.oAuthClientId
164 },
716adfae 165 user: token.User,
e307e4fc
C
166 token
167 } as OAuthTokenInfo
168 })
169 .catch(err => {
170 logger.error('getRefreshToken error.', { err })
171 throw err
172 })
feb4bdfd
C
173 }
174
b49f22d8 175 static getByTokenAndPopulateUser (bearerToken: string): Promise<MOAuthTokenUser> {
3fd3ab2d
C
176 const query = {
177 where: {
178 accessToken: bearerToken
d48ff09d 179 }
3fd3ab2d 180 }
2f372a86 181
3acc5084
C
182 return OAuthTokenModel.scope(ScopeNames.WITH_USER)
183 .findOne(query)
184 .then(token => {
453e83ea 185 if (!token) return null
69b0a27c 186
453e83ea 187 return Object.assign(token, { user: token.User })
3acc5084 188 })
feb4bdfd
C
189 }
190
b49f22d8 191 static getByRefreshTokenAndPopulateUser (refreshToken: string): Promise<MOAuthTokenUser> {
3fd3ab2d
C
192 const query = {
193 where: {
e307e4fc 194 refreshToken
d48ff09d 195 }
3fd3ab2d 196 }
feb4bdfd 197
91411dba 198 return OAuthTokenModel.scope(ScopeNames.WITH_USER)
d48ff09d
C
199 .findOne(query)
200 .then(token => {
e307e4fc 201 if (!token) return undefined
453e83ea
C
202
203 return Object.assign(token, { user: token.User })
d48ff09d 204 })
feb4bdfd 205 }
f8b8c36b 206
e6921918 207 static deleteUserToken (userId: number, t?: Transaction) {
f43db2f4
C
208 TokensCache.Instance.deleteUserToken(userId)
209
f8b8c36b
C
210 const query = {
211 where: {
212 userId
e6921918
C
213 },
214 transaction: t
f8b8c36b
C
215 }
216
217 return OAuthTokenModel.destroy(query)
218 }
2f372a86 219}