Stronger model 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/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 }
34
35 enum ScopeNames {
36   WITH_USER = 'WITH_USER'
37 }
38
39 @Scopes(() => ({
40   [ScopeNames.WITH_USER]: {
41     include: [
42       {
43         model: UserModel.unscoped(),
44         required: true,
45         include: [
46           {
47             attributes: [ 'id' ],
48             model: AccountModel.unscoped(),
49             required: true,
50             include: [
51               {
52                 attributes: [ 'id', 'url' ],
53                 model: ActorModel.unscoped(),
54                 required: true
55               }
56             ]
57           }
58         ]
59       }
60     ]
61   }
62 }))
63 @Table({
64   tableName: 'oAuthToken',
65   indexes: [
66     {
67       fields: [ 'refreshToken' ],
68       unique: true
69     },
70     {
71       fields: [ 'accessToken' ],
72       unique: true
73     },
74     {
75       fields: [ 'userId' ]
76     },
77     {
78       fields: [ 'oAuthClientId' ]
79     }
80   ]
81 })
82 export class OAuthTokenModel extends Model<OAuthTokenModel> {
83
84   @AllowNull(false)
85   @Column
86   accessToken: string
87
88   @AllowNull(false)
89   @Column
90   accessTokenExpiresAt: Date
91
92   @AllowNull(false)
93   @Column
94   refreshToken: string
95
96   @AllowNull(false)
97   @Column
98   refreshTokenExpiresAt: Date
99
100   @CreatedAt
101   createdAt: Date
102
103   @UpdatedAt
104   updatedAt: Date
105
106   @ForeignKey(() => UserModel)
107   @Column
108   userId: number
109
110   @BelongsTo(() => UserModel, {
111     foreignKey: {
112       allowNull: false
113     },
114     onDelete: 'cascade'
115   })
116   User: UserModel
117
118   @ForeignKey(() => OAuthClientModel)
119   @Column
120   oAuthClientId: number
121
122   @BelongsTo(() => OAuthClientModel, {
123     foreignKey: {
124       allowNull: false
125     },
126     onDelete: 'cascade'
127   })
128   OAuthClients: OAuthClientModel[]
129
130   @AfterUpdate
131   @AfterDestroy
132   static removeTokenCache (token: OAuthTokenModel) {
133     return clearCacheByToken(token.accessToken)
134   }
135
136   static getByRefreshTokenAndPopulateClient (refreshToken: string) {
137     const query = {
138       where: {
139         refreshToken: refreshToken
140       },
141       include: [ OAuthClientModel ]
142     }
143
144     return OAuthTokenModel.findOne(query)
145       .then(token => {
146         if (!token) return null
147
148         return {
149           refreshToken: token.refreshToken,
150           refreshTokenExpiresAt: token.refreshTokenExpiresAt,
151           client: {
152             id: token.oAuthClientId
153           },
154           user: {
155             id: token.userId
156           }
157         } as OAuthTokenInfo
158       })
159       .catch(err => {
160         logger.error('getRefreshToken error.', { err })
161         throw err
162       })
163   }
164
165   static getByTokenAndPopulateUser (bearerToken: string): Bluebird<MOAuthTokenUser> {
166     const query = {
167       where: {
168         accessToken: bearerToken
169       }
170     }
171
172     return OAuthTokenModel.scope(ScopeNames.WITH_USER)
173                           .findOne(query)
174                           .then(token => {
175                             if (!token) return null
176
177                             return Object.assign(token, { user: token.User })
178                           })
179   }
180
181   static getByRefreshTokenAndPopulateUser (refreshToken: string): Bluebird<MOAuthTokenUser> {
182     const query = {
183       where: {
184         refreshToken: refreshToken
185       }
186     }
187
188     return OAuthTokenModel.scope(ScopeNames.WITH_USER)
189       .findOne(query)
190       .then(token => {
191         if (!token) return new OAuthTokenModel()
192
193         return Object.assign(token, { user: token.User })
194       })
195   }
196
197   static deleteUserToken (userId: number, t?: Transaction) {
198     const query = {
199       where: {
200         userId
201       },
202       transaction: t
203     }
204
205     return OAuthTokenModel.destroy(query)
206   }
207 }