ニジカ投稿局 https://tv.nizika.tv
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

oauth-token.ts 4.9 KiB

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