Split types and typings
[oweals/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/types/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: token.User,
168                               token
169                             } as OAuthTokenInfo
170                           })
171                           .catch(err => {
172                             logger.error('getRefreshToken error.', { err })
173                             throw err
174                           })
175   }
176
177   static getByTokenAndPopulateUser (bearerToken: string): Bluebird<MOAuthTokenUser> {
178     const query = {
179       where: {
180         accessToken: bearerToken
181       }
182     }
183
184     return OAuthTokenModel.scope(ScopeNames.WITH_USER)
185                           .findOne(query)
186                           .then(token => {
187                             if (!token) return null
188
189                             return Object.assign(token, { user: token.User })
190                           })
191   }
192
193   static getByRefreshTokenAndPopulateUser (refreshToken: string): Bluebird<MOAuthTokenUser> {
194     const query = {
195       where: {
196         refreshToken
197       }
198     }
199
200     return OAuthTokenModel.scope(ScopeNames.WITH_USER)
201       .findOne(query)
202       .then(token => {
203         if (!token) return undefined
204
205         return Object.assign(token, { user: token.User })
206       })
207   }
208
209   static deleteUserToken (userId: number, t?: Transaction) {
210     const query = {
211       where: {
212         userId
213       },
214       transaction: t
215     }
216
217     return OAuthTokenModel.destroy(query)
218   }
219 }