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