jobType: JobTypeClient = 'all'
jobTypes: JobTypeClient[] = [
'all',
+
'activitypub-follow',
'activitypub-http-broadcast',
'activitypub-http-fetcher',
'activitypub-http-unicast',
'activitypub-refresher',
+ 'actor-keys',
'email',
'video-file-import',
'video-import',
label: $localize`:A variant of Trending videos based on the number of recent interactions, minus user history:Best`,
iconName: 'award',
value: 'best',
- tooltip: $localize`Videos totalizing the most interactions for recent videos, minus user history`,
+ tooltip: $localize`Videos with the most interactions for recent videos, minus user history`,
hidden: true
},
{
label: $localize`:A variant of Trending videos based on the number of recent interactions:Hot`,
iconName: 'flame',
value: 'hot',
- tooltip: $localize`Videos totalizing the most interactions for recent videos`,
+ tooltip: $localize`Videos with the most interactions for recent videos`,
hidden: true
},
{
label: $localize`:Main variant of Trending videos based on number of recent views:Views`,
iconName: 'trending',
value: 'most-viewed',
- tooltip: $localize`Videos totalizing the most views during the last 24 hours`
+ tooltip: $localize`Videos with the most views during the last 24 hours`
},
{
label: $localize`:A variant of Trending videos based on the number of likes:Likes`,
id: account.id
}
}
- }).end()
+ })
}
async function registerUser (req: express.Request, res: express.Response) {
import { getServerActor } from '@server/models/application/application'
import { MChannelAccountDefault } from '@server/types/models'
import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared'
+import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
import { auditLoggerFactory, getAuditIdFromRes, VideoChannelAuditView } from '../../helpers/audit-logger'
import { resetSequelizeInstance } from '../../helpers/database-utils'
import { buildNSFWFilter, createReqFiles, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
import { CONFIG } from '../../initializers/config'
import { MIMETYPES } from '../../initializers/constants'
import { sequelizeTypescript } from '../../initializers/database'
-import { setAsyncActorKeys } from '../../lib/activitypub/actor'
import { sendUpdateActor } from '../../lib/activitypub/send'
import { deleteLocalActorAvatarFile, updateLocalActorAvatarFile } from '../../lib/avatar'
import { JobQueue } from '../../lib/job-queue'
import { VideoModel } from '../../models/video/video'
import { VideoChannelModel } from '../../models/video/video-channel'
import { VideoPlaylistModel } from '../../models/video/video-playlist'
-import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
const auditLogger = auditLoggerFactory('channels')
const reqAvatarFile = createReqFiles([ 'avatarfile' ], MIMETYPES.IMAGE.MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.TMP_DIR })
return createLocalVideoChannel(videoChannelInfo, account, t)
})
- setAsyncActorKeys(videoChannelCreated.Actor)
- .catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.url, { err }))
+ const payload = { actorId: videoChannelCreated.actorId }
+ await JobQueue.Instance.createJobWithPromise({ type: 'actor-keys', payload })
auditLogger.create(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelCreated.toFormattedJSON()))
logger.info('Video channel %s created.', videoChannelCreated.Actor.url)
-import { randomInt } from '../../shared/core-utils/miscs/miscs'
import { CronRepeatOptions, EveryRepeatOptions } from 'bull'
import { randomBytes } from 'crypto'
import { invert } from 'lodash'
import { join } from 'path'
+import { randomInt } from '../../shared/core-utils/miscs/miscs'
import {
AbuseState,
JobType,
// ---------------------------------------------------------------------------
-const LAST_MIGRATION_VERSION = 600
+const LAST_MIGRATION_VERSION = 605
// ---------------------------------------------------------------------------
'video-transcoding': 1,
'video-import': 1,
'email': 5,
+ 'actor-keys': 3,
'videos-views': 1,
'activitypub-refresher': 1,
'video-redundancy': 1,
'activitypub-follow': 1,
'video-file-import': 1,
'email': 5,
+ 'actor-keys': 1,
'videos-views': 1,
'activitypub-refresher': 1,
'video-redundancy': 1,
'video-transcoding': 1000 * 3600 * 48, // 2 days, transcoding could be long
'video-import': 1000 * 3600 * 2, // 2 hours
'email': 60000 * 10, // 10 minutes
+ 'actor-keys': 60000 * 20, // 20 minutes
'videos-views': undefined, // Unlimited
'activitypub-refresher': 60000 * 10, // 10 minutes
'video-redundancy': 1000 * 3600 * 3, // 3 hours
--- /dev/null
+import * as Sequelize from 'sequelize'
+import { createPrivateKey, getPublicKey } from '../../helpers/core-utils'
+import { PRIVATE_RSA_KEY_SIZE } from '../constants'
+
+async function up (utils: {
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
+ db: any
+}): Promise<void> {
+
+ {
+ const query = 'SELECT * FROM "actor" WHERE "serverId" IS NULL AND "publicKey" IS NULL'
+ const options = { type: Sequelize.QueryTypes.SELECT as Sequelize.QueryTypes.SELECT }
+ const actors = await utils.sequelize.query<any>(query, options)
+
+ for (const actor of actors) {
+ const { key } = await createPrivateKey(PRIVATE_RSA_KEY_SIZE)
+ const { publicKey } = await getPublicKey(key)
+
+ const queryUpdate = `UPDATE "actor" SET "publicKey" = '${publicKey}', "privateKey" = '${key}' WHERE id = ${actor.id}`
+ await utils.sequelize.query(queryUpdate)
+ }
+ }
+}
+
+function down (options) {
+ throw new Error('Not implemented.')
+}
+
+export {
+ up,
+ down
+}
import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
// Set account keys, this could be long so process after the account creation and do not block the client
-function setAsyncActorKeys <T extends MActor> (actor: T) {
- return createPrivateAndPublicKeys()
- .then(({ publicKey, privateKey }) => {
- actor.publicKey = publicKey
- actor.privateKey = privateKey
- return actor.save()
- })
- .catch(err => {
- logger.error('Cannot set public/private keys of actor %d.', actor.url, { err })
- return actor
- })
+async function generateAndSaveActorKeys <T extends MActor> (actor: T) {
+ const { publicKey, privateKey } = await createPrivateAndPublicKeys()
+
+ actor.publicKey = publicKey
+ actor.privateKey = privateKey
+
+ return actor.save()
}
function getOrCreateActorAndServerAndModel (
export {
getOrCreateActorAndServerAndModel,
buildActorInstance,
- setAsyncActorKeys,
+ generateAndSaveActorKeys,
fetchActorTotalItems,
getAvatarInfoIfExists,
updateActorInstance,
--- /dev/null
+import * as Bull from 'bull'
+import { generateAndSaveActorKeys } from '@server/lib/activitypub/actor'
+import { ActorModel } from '@server/models/activitypub/actor'
+import { ActorKeysPayload } from '@shared/models'
+import { logger } from '../../../helpers/logger'
+
+async function processActorKeys (job: Bull.Job) {
+ const payload = job.data as ActorKeysPayload
+ logger.info('Processing email in job %d.', job.id)
+
+ const actor = await ActorModel.load(payload.actorId)
+
+ await generateAndSaveActorKeys(actor)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+ processActorKeys
+}
ActivitypubHttpBroadcastPayload,
ActivitypubHttpFetcherPayload,
ActivitypubHttpUnicastPayload,
+ ActorKeysPayload,
EmailPayload,
JobState,
JobType,
import { processActivityPubHttpFetcher } from './handlers/activitypub-http-fetcher'
import { processActivityPubHttpUnicast } from './handlers/activitypub-http-unicast'
import { refreshAPObject } from './handlers/activitypub-refresher'
+import { processActorKeys } from './handlers/actor-keys'
import { processEmail } from './handlers/email'
import { processVideoFileImport } from './handlers/video-file-import'
import { processVideoImport } from './handlers/video-import'
{ type: 'activitypub-refresher', payload: RefreshPayload } |
{ type: 'videos-views', payload: {} } |
{ type: 'video-live-ending', payload: VideoLiveEndingPayload } |
+ { type: 'actor-keys', payload: ActorKeysPayload } |
{ type: 'video-redundancy', payload: VideoRedundancyPayload }
type CreateJobOptions = {
'videos-views': processVideosViews,
'activitypub-refresher': refreshAPObject,
'video-live-ending': processVideoLiveEnding,
+ 'actor-keys': processActorKeys,
'video-redundancy': processVideoRedundancy
}
'videos-views',
'activitypub-refresher',
'video-redundancy',
+ 'actor-keys',
'video-live-ending'
]
import { ActorModel } from '../models/activitypub/actor'
import { MAccountDefault, MActorDefault, MChannelActor } from '../types/models'
import { MUser, MUserDefault, MUserId } from '../types/models/user'
-import { buildActorInstance, setAsyncActorKeys } from './activitypub/actor'
+import { buildActorInstance, generateAndSaveActorKeys } from './activitypub/actor'
import { getLocalAccountActivityPubUrl } from './activitypub/url'
import { Emailer } from './emailer'
import { LiveManager } from './live-manager'
})
const [ accountActorWithKeys, channelActorWithKeys ] = await Promise.all([
- setAsyncActorKeys(account.Actor),
- setAsyncActorKeys(videoChannel.Actor)
+ generateAndSaveActorKeys(account.Actor),
+ generateAndSaveActorKeys(videoChannel.Actor)
])
account.Actor = accountActorWithKeys
type: 'Application'
})
- accountCreated.Actor = await setAsyncActorKeys(accountCreated.Actor)
+ accountCreated.Actor = await generateAndSaveActorKeys(accountCreated.Actor)
return accountCreated
}
| 'activitypub-refresher'
| 'video-redundancy'
| 'video-live-ending'
+ | 'actor-keys'
export interface Job {
id: number
export interface VideoLiveEndingPayload {
videoId: number
}
+
+export interface ActorKeysPayload {
+ actorId: number
+}