actor.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import * as validator from 'validator'
  2. import { CONSTRAINTS_FIELDS } from '../../../initializers/constants'
  3. import { exists, isArray } from '../misc'
  4. import { truncate } from 'lodash'
  5. import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc'
  6. import { isHostValid } from '../servers'
  7. function isActorEndpointsObjectValid (endpointObject: any) {
  8. return isActivityPubUrlValid(endpointObject.sharedInbox)
  9. }
  10. function isActorPublicKeyObjectValid (publicKeyObject: any) {
  11. return isActivityPubUrlValid(publicKeyObject.id) &&
  12. isActivityPubUrlValid(publicKeyObject.owner) &&
  13. isActorPublicKeyValid(publicKeyObject.publicKeyPem)
  14. }
  15. function isActorTypeValid (type: string) {
  16. return type === 'Person' || type === 'Application' || type === 'Group'
  17. }
  18. function isActorPublicKeyValid (publicKey: string) {
  19. return exists(publicKey) &&
  20. typeof publicKey === 'string' &&
  21. publicKey.startsWith('-----BEGIN PUBLIC KEY-----') &&
  22. publicKey.indexOf('-----END PUBLIC KEY-----') !== -1 &&
  23. validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY)
  24. }
  25. const actorNameAlphabet = '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\\-_.]'
  26. const actorNameRegExp = new RegExp(`^${actorNameAlphabet}+$`)
  27. function isActorPreferredUsernameValid (preferredUsername: string) {
  28. return exists(preferredUsername) && validator.matches(preferredUsername, actorNameRegExp)
  29. }
  30. function isActorPrivateKeyValid (privateKey: string) {
  31. return exists(privateKey) &&
  32. typeof privateKey === 'string' &&
  33. privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') &&
  34. // Sometimes there is a \n at the end, so just assert the string contains the end mark
  35. privateKey.indexOf('-----END RSA PRIVATE KEY-----') !== -1 &&
  36. validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY)
  37. }
  38. function isActorObjectValid (actor: any) {
  39. return exists(actor) &&
  40. isActivityPubUrlValid(actor.id) &&
  41. isActorTypeValid(actor.type) &&
  42. isActivityPubUrlValid(actor.following) &&
  43. isActivityPubUrlValid(actor.followers) &&
  44. isActivityPubUrlValid(actor.inbox) &&
  45. isActivityPubUrlValid(actor.outbox) &&
  46. isActorPreferredUsernameValid(actor.preferredUsername) &&
  47. isActivityPubUrlValid(actor.url) &&
  48. isActorPublicKeyObjectValid(actor.publicKey) &&
  49. isActorEndpointsObjectValid(actor.endpoints) &&
  50. setValidAttributedTo(actor) &&
  51. // If this is not an account, it should be attributed to an account
  52. // In PeerTube we use this to attach a video channel to a specific account
  53. (actor.type === 'Person' || actor.attributedTo.length !== 0)
  54. }
  55. function isActorFollowingCountValid (value: string) {
  56. return exists(value) && validator.isInt('' + value, { min: 0 })
  57. }
  58. function isActorFollowersCountValid (value: string) {
  59. return exists(value) && validator.isInt('' + value, { min: 0 })
  60. }
  61. function isActorDeleteActivityValid (activity: any) {
  62. return isBaseActivityValid(activity, 'Delete')
  63. }
  64. function sanitizeAndCheckActorObject (object: any) {
  65. normalizeActor(object)
  66. return isActorObjectValid(object)
  67. }
  68. function normalizeActor (actor: any) {
  69. if (!actor || !actor.url) return
  70. if (typeof actor.url !== 'string') {
  71. actor.url = actor.url.href || actor.url.url
  72. }
  73. if (actor.summary && typeof actor.summary === 'string') {
  74. actor.summary = truncate(actor.summary, { length: CONSTRAINTS_FIELDS.USERS.DESCRIPTION.max })
  75. if (actor.summary.length < CONSTRAINTS_FIELDS.USERS.DESCRIPTION.min) {
  76. actor.summary = null
  77. }
  78. }
  79. return
  80. }
  81. function isValidActorHandle (handle: string) {
  82. if (!exists(handle)) return false
  83. const parts = handle.split('@')
  84. if (parts.length !== 2) return false
  85. return isHostValid(parts[1])
  86. }
  87. function areValidActorHandles (handles: string[]) {
  88. return isArray(handles) && handles.every(h => isValidActorHandle(h))
  89. }
  90. // ---------------------------------------------------------------------------
  91. export {
  92. normalizeActor,
  93. actorNameAlphabet,
  94. areValidActorHandles,
  95. isActorEndpointsObjectValid,
  96. isActorPublicKeyObjectValid,
  97. isActorTypeValid,
  98. isActorPublicKeyValid,
  99. isActorPreferredUsernameValid,
  100. isActorPrivateKeyValid,
  101. isActorObjectValid,
  102. isActorFollowingCountValid,
  103. isActorFollowersCountValid,
  104. isActorDeleteActivityValid,
  105. sanitizeAndCheckActorObject,
  106. isValidActorHandle
  107. }