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