forked from FoundKeyGang/FoundKey
activitypub: simplify some URI/id related checks
followup on previous commit
This commit is contained in:
parent
3582fd8260
commit
ef53ec276a
3 changed files with 32 additions and 25 deletions
|
@ -1,5 +1,5 @@
|
||||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||||
import { getApType, IUpdate, isActor } from '@/remote/activitypub/type.js';
|
import { getApId, getApType, IUpdate, isActor } from '@/remote/activitypub/type.js';
|
||||||
import { apLogger } from '@/remote/activitypub/logger.js';
|
import { apLogger } from '@/remote/activitypub/logger.js';
|
||||||
import { updateQuestion } from '@/remote/activitypub/models/question.js';
|
import { updateQuestion } from '@/remote/activitypub/models/question.js';
|
||||||
import { Resolver } from '@/remote/activitypub/resolver.js';
|
import { Resolver } from '@/remote/activitypub/resolver.js';
|
||||||
|
@ -21,7 +21,11 @@ export default async (actor: CacheableRemoteUser, activity: IUpdate, resolver: R
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isActor(object)) {
|
if (isActor(object)) {
|
||||||
await updatePerson(actor.uri!, resolver, object);
|
if (actor.uri !== getApId(object)) {
|
||||||
|
return 'skip: actor id !== updated actor id';
|
||||||
|
}
|
||||||
|
|
||||||
|
await updatePerson(object, resolver);
|
||||||
return 'ok: Person updated';
|
return 'ok: Person updated';
|
||||||
} else if (getApType(object) === 'Question') {
|
} else if (getApType(object) === 'Question') {
|
||||||
await updateQuestion(object, resolver).catch(e => console.log(e));
|
await updateQuestion(object, resolver).catch(e => console.log(e));
|
||||||
|
|
|
@ -28,9 +28,7 @@ import { extractApHashtags } from './tag.js';
|
||||||
import { extractPollFromQuestion } from './question.js';
|
import { extractPollFromQuestion } from './question.js';
|
||||||
import { extractApMentions } from './mention.js';
|
import { extractApMentions } from './mention.js';
|
||||||
|
|
||||||
export function validateNote(object: any, uri: string): Error | null {
|
export function validateNote(object: IObject): Error | null {
|
||||||
const expectHost = extractDbHost(uri);
|
|
||||||
|
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
return new Error('invalid Note: object is null');
|
return new Error('invalid Note: object is null');
|
||||||
}
|
}
|
||||||
|
@ -39,12 +37,20 @@ export function validateNote(object: any, uri: string): Error | null {
|
||||||
return new Error(`invalid Note: invalid object type ${getApType(object)}`);
|
return new Error(`invalid Note: invalid object type ${getApType(object)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.id && extractDbHost(object.id) !== expectHost) {
|
const id = getApId(object);
|
||||||
return new Error(`invalid Note: id has different host. expected: ${expectHost}, actual: ${extractDbHost(object.id)}`);
|
if (id == null) {
|
||||||
|
// Only transient objects or anonymous objects may not have an id or an id that is explicitly null.
|
||||||
|
// We consider all Notes as not transient and not anonymous so require ids for them.
|
||||||
|
return new Error(`invalid Note: id required but not present`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.attributedTo && extractDbHost(getOneApId(object.attributedTo)) !== expectHost) {
|
// Check that the server is authorized to act on behalf of this author.
|
||||||
return new Error(`invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${extractDbHost(object.attributedTo)}`);
|
const expectHost = extractDbHost(id);
|
||||||
|
const attributedToHost = object.attributedTo
|
||||||
|
? extractDbHost(getOneApId(object.attributedTo))
|
||||||
|
: null;
|
||||||
|
if (attributedToHost !== expectHost) {
|
||||||
|
return new Error(`invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${attributedToHost}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -64,10 +70,9 @@ export async function fetchNote(object: string | IObject): Promise<Note | null>
|
||||||
* Noteを作成します。
|
* Noteを作成します。
|
||||||
*/
|
*/
|
||||||
export async function createNote(value: string | IObject, resolver: Resolver, silent = false): Promise<Note | null> {
|
export async function createNote(value: string | IObject, resolver: Resolver, silent = false): Promise<Note | null> {
|
||||||
const object: any = await resolver.resolve(value);
|
const object: IObject = await resolver.resolve(value);
|
||||||
|
|
||||||
const entryUri = getApId(value);
|
const err = validateNote(object);
|
||||||
const err = validateNote(object, entryUri);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
apLogger.error(`${err.message}`, {
|
apLogger.error(`${err.message}`, {
|
||||||
resolver: {
|
resolver: {
|
||||||
|
|
|
@ -39,8 +39,7 @@ const summaryLength = 2048;
|
||||||
* @param x Fetched object
|
* @param x Fetched object
|
||||||
* @param uri Fetch target URI
|
* @param uri Fetch target URI
|
||||||
*/
|
*/
|
||||||
function validateActor(x: IObject, uri: string): IActor {
|
function validateActor(x: IObject): IActor {
|
||||||
const expectHost = toPuny(new URL(uri).hostname);
|
|
||||||
|
|
||||||
if (x == null) {
|
if (x == null) {
|
||||||
throw new Error('invalid Actor: object is null');
|
throw new Error('invalid Actor: object is null');
|
||||||
|
@ -50,7 +49,10 @@ function validateActor(x: IObject, uri: string): IActor {
|
||||||
throw new Error(`invalid Actor type '${x.type}'`);
|
throw new Error(`invalid Actor type '${x.type}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(typeof x.id === 'string' && x.id.length > 0)) {
|
const uri = getApId(x);
|
||||||
|
if (uri == null) {
|
||||||
|
// Only transient objects or anonymous objects may not have an id or an id that is explicitly null.
|
||||||
|
// We consider all actors as not transient and not anonymous so require ids for them.
|
||||||
throw new Error('invalid Actor: wrong id');
|
throw new Error('invalid Actor: wrong id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,16 +80,12 @@ function validateActor(x: IObject, uri: string): IActor {
|
||||||
x.summary = truncate(x.summary, summaryLength);
|
x.summary = truncate(x.summary, summaryLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
const idHost = toPuny(new URL(x.id!).hostname);
|
|
||||||
if (idHost !== expectHost) {
|
|
||||||
throw new Error('invalid Actor: id has different host');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x.publicKey) {
|
if (x.publicKey) {
|
||||||
if (typeof x.publicKey.id !== 'string') {
|
if (typeof x.publicKey.id !== 'string') {
|
||||||
throw new Error('invalid Actor: publicKey.id is not a string');
|
throw new Error('invalid Actor: publicKey.id is not a string');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const expectHost = extractDbHost(uri);
|
||||||
const publicKeyIdHost = toPuny(new URL(x.publicKey.id).hostname);
|
const publicKeyIdHost = toPuny(new URL(x.publicKey.id).hostname);
|
||||||
if (publicKeyIdHost !== expectHost) {
|
if (publicKeyIdHost !== expectHost) {
|
||||||
throw new Error('invalid Actor: publicKey.id has different host');
|
throw new Error('invalid Actor: publicKey.id has different host');
|
||||||
|
@ -140,7 +138,7 @@ export async function createPerson(uri: string, resolver: Resolver): Promise<Use
|
||||||
|
|
||||||
const object = await resolver.resolve(uri) as any;
|
const object = await resolver.resolve(uri) as any;
|
||||||
|
|
||||||
const person = validateActor(object, uri);
|
const person = validateActor(object);
|
||||||
|
|
||||||
apLogger.info(`Creating the Person: ${person.id}`);
|
apLogger.info(`Creating the Person: ${person.id}`);
|
||||||
|
|
||||||
|
@ -278,8 +276,8 @@ export async function createPerson(uri: string, resolver: Resolver): Promise<Use
|
||||||
* @param resolver Resolver
|
* @param resolver Resolver
|
||||||
* @param hint Hint of Person object (If this value is a valid Person, it is used for updating without Remote resolve.)
|
* @param hint Hint of Person object (If this value is a valid Person, it is used for updating without Remote resolve.)
|
||||||
*/
|
*/
|
||||||
export async function updatePerson(uri: string, resolver: Resolver, hint?: IObject): Promise<void> {
|
export async function updatePerson(value: IObject | string, resolver: Resolver): Promise<void> {
|
||||||
if (typeof uri !== 'string') throw new Error('uri is not string');
|
const uri = getApId(value);
|
||||||
|
|
||||||
// URIがこのサーバーを指しているならスキップ
|
// URIがこのサーバーを指しているならスキップ
|
||||||
if (uri.startsWith(config.url + '/')) {
|
if (uri.startsWith(config.url + '/')) {
|
||||||
|
@ -294,9 +292,9 @@ export async function updatePerson(uri: string, resolver: Resolver, hint?: IObje
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
const object = hint || await resolver.resolve(uri);
|
const object = await resolver.resolve(value);
|
||||||
|
|
||||||
const person = validateActor(object, uri);
|
const person = validateActor(object);
|
||||||
|
|
||||||
apLogger.info(`Updating the Person: ${person.id}`);
|
apLogger.info(`Updating the Person: ${person.id}`);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue