oauth-token.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. export type OAuthTokenInfo = {
  24. refreshToken: string
  25. refreshTokenExpiresAt: Date
  26. client: {
  27. id: number
  28. }
  29. user: {
  30. id: number
  31. }
  32. token: MOAuthTokenUser
  33. }
  34. enum ScopeNames {
  35. WITH_USER = 'WITH_USER'
  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. @AllowNull(false)
  82. @Column
  83. accessToken: string
  84. @AllowNull(false)
  85. @Column
  86. accessTokenExpiresAt: Date
  87. @AllowNull(false)
  88. @Column
  89. refreshToken: string
  90. @AllowNull(false)
  91. @Column
  92. refreshTokenExpiresAt: Date
  93. @Column
  94. authName: string
  95. @CreatedAt
  96. createdAt: Date
  97. @UpdatedAt
  98. updatedAt: Date
  99. @ForeignKey(() => UserModel)
  100. @Column
  101. userId: number
  102. @BelongsTo(() => UserModel, {
  103. foreignKey: {
  104. allowNull: false
  105. },
  106. onDelete: 'cascade'
  107. })
  108. User: UserModel
  109. @ForeignKey(() => OAuthClientModel)
  110. @Column
  111. oAuthClientId: number
  112. @BelongsTo(() => OAuthClientModel, {
  113. foreignKey: {
  114. allowNull: false
  115. },
  116. onDelete: 'cascade'
  117. })
  118. OAuthClients: OAuthClientModel[]
  119. @AfterUpdate
  120. @AfterDestroy
  121. static removeTokenCache (token: OAuthTokenModel) {
  122. return clearCacheByToken(token.accessToken)
  123. }
  124. static loadByRefreshToken (refreshToken: string) {
  125. const query = {
  126. where: { refreshToken }
  127. }
  128. return OAuthTokenModel.findOne(query)
  129. }
  130. static getByRefreshTokenAndPopulateClient (refreshToken: string) {
  131. const query = {
  132. where: {
  133. refreshToken
  134. },
  135. include: [ OAuthClientModel ]
  136. }
  137. return OAuthTokenModel.scope(ScopeNames.WITH_USER)
  138. .findOne(query)
  139. .then(token => {
  140. if (!token) return null
  141. return {
  142. refreshToken: token.refreshToken,
  143. refreshTokenExpiresAt: token.refreshTokenExpiresAt,
  144. client: {
  145. id: token.oAuthClientId
  146. },
  147. user: token.User,
  148. token
  149. } as OAuthTokenInfo
  150. })
  151. .catch(err => {
  152. logger.error('getRefreshToken error.', { err })
  153. throw err
  154. })
  155. }
  156. static getByTokenAndPopulateUser (bearerToken: string): Bluebird<MOAuthTokenUser> {
  157. const query = {
  158. where: {
  159. accessToken: bearerToken
  160. }
  161. }
  162. return OAuthTokenModel.scope(ScopeNames.WITH_USER)
  163. .findOne(query)
  164. .then(token => {
  165. if (!token) return null
  166. return Object.assign(token, { user: token.User })
  167. })
  168. }
  169. static getByRefreshTokenAndPopulateUser (refreshToken: string): Bluebird<MOAuthTokenUser> {
  170. const query = {
  171. where: {
  172. refreshToken
  173. }
  174. }
  175. return OAuthTokenModel.scope(ScopeNames.WITH_USER)
  176. .findOne(query)
  177. .then(token => {
  178. if (!token) return undefined
  179. return Object.assign(token, { user: token.User })
  180. })
  181. }
  182. static deleteUserToken (userId: number, t?: Transaction) {
  183. const query = {
  184. where: {
  185. userId
  186. },
  187. transaction: t
  188. }
  189. return OAuthTokenModel.destroy(query)
  190. }
  191. }