Skip to content

Commit

Permalink
enhance(dev): non-production環境でhttpサーバー間でもユーザー、ノートの連合が可能なように (#10717)
Browse files Browse the repository at this point in the history
* enhance(dev): non-production環境でhttpサーバー間でもユーザー、ノートの連合が可能なように

* refactor (use checkHttps)

* MISSKEY_WEBFINGER_USE_HTTP

* Environment Variable readme

* NEVER USE IN PRODUCTION

* fix punyHost
  • Loading branch information
tamaina authored Apr 29, 2023
1 parent 2d3d986 commit 09764b9
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 13 deletions.
5 changes: 5 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ pnpm jest -- foo.ts
### e2e tests
TODO

## Environment Variable

- `MISSKEY_CONFIG_YML`: Specify the file path of config.yml instead of default.yml (e.g. `2nd.yml`).
- `MISSKEY_WEBFINGER_USE_HTTP`: If it's set true, WebFinger requests will be http instead of https, useful for testing federation between servers in localhost. NEVER USE IN PRODUCTION.

## Continuous integration
Misskey uses GitHub Actions for executing automated tests.
Configuration files are located in [`/.github/workflows`](/.github/workflows).
Expand Down
3 changes: 2 additions & 1 deletion packages/backend/src/core/WebfingerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export class WebfingerService {
const m = query.match(/^([^@]+)@(.*)/);
if (m) {
const hostname = m[2];
return `https://${hostname}/.well-known/webfinger?` + urlQuery({ resource: `acct:${query}` });
const useHttp = process.env.MISSKEY_WEBFINGER_USE_HTTP && process.env.MISSKEY_WEBFINGER_USE_HTTP.toLowerCase() === 'true';
return `http${useHttp ? '' : 's'}://${hostname}/.well-known/webfinger?${urlQuery({ resource: `acct:${query}` })}`;
}

throw new Error(`Invalid query (${query})`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
import { ApResolverService } from '../ApResolverService.js';
import { ApLoggerService } from '../ApLoggerService.js';
import { checkHttps } from '@/misc/check-https.js';

@Injectable()
export class ApImageService {
Expand Down Expand Up @@ -48,8 +49,8 @@ export class ApImageService {
throw new Error('invalid image: url not privided');
}

if (!image.url.startsWith('https://')) {
throw new Error('invalid image: unexpected shcema of url: ' + image.url);
if (!checkHttps(image.url)) {
throw new Error('invalid image: unexpected schema of url: ' + image.url);
}

this.logger.info(`Creating the Image: ${image.url}`);
Expand Down
5 changes: 3 additions & 2 deletions packages/backend/src/core/activitypub/models/ApNoteService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { ApQuestionService } from './ApQuestionService.js';
import { ApImageService } from './ApImageService.js';
import type { Resolver } from '../ApResolverService.js';
import type { IObject, IPost } from '../type.js';
import { checkHttps } from '@/misc/check-https.js';

@Injectable()
export class ApNoteService {
Expand Down Expand Up @@ -130,13 +131,13 @@ export class ApNoteService {

this.logger.debug(`Note fetched: ${JSON.stringify(note, null, 2)}`);

if (note.id && !note.id.startsWith('https://')) {
if (note.id && !checkHttps(note.id)) {
throw new Error('unexpected shcema of note.id: ' + note.id);
}

const url = getOneApHrefNullable(note.url);

if (url && !url.startsWith('https://')) {
if (url && !checkHttps(url)) {
throw new Error('unexpected shcema of note url: ' + url);
}

Expand Down
23 changes: 15 additions & 8 deletions packages/backend/src/core/activitypub/models/ApPersonService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import type { ApLoggerService } from '../ApLoggerService.js';
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
import type { ApImageService } from './ApImageService.js';
import type { IActor, IObject } from '../type.js';
import { checkHttps } from '@/misc/check-https.js';

const nameLength = 128;
const summaryLength = 2048;
Expand Down Expand Up @@ -134,14 +135,20 @@ export class ApPersonService implements OnModuleInit {
this.logger = this.apLoggerService.logger;
}

private punyHost(url: string): string {
const urlObj = new URL(url);
const host = `${this.utilityService.toPuny(urlObj.hostname)}${urlObj.port.length > 0 ? ':' + urlObj.port : ''}`;
return host;
}

/**
* Validate and convert to actor object
* @param x Fetched object
* @param uri Fetch target URI
*/
@bindThis
private validateActor(x: IObject, uri: string): IActor {
const expectHost = this.utilityService.toPuny(new URL(uri).hostname);
const expectHost = this.punyHost(uri);

if (x == null) {
throw new Error('invalid Actor: object is null');
Expand Down Expand Up @@ -182,7 +189,7 @@ export class ApPersonService implements OnModuleInit {
x.summary = truncate(x.summary, summaryLength);
}

const idHost = this.utilityService.toPuny(new URL(x.id!).hostname);
const idHost = this.punyHost(x.id);
if (idHost !== expectHost) {
throw new Error('invalid Actor: id has different host');
}
Expand All @@ -192,7 +199,7 @@ export class ApPersonService implements OnModuleInit {
throw new Error('invalid Actor: publicKey.id is not a string');
}

const publicKeyIdHost = this.utilityService.toPuny(new URL(x.publicKey.id).hostname);
const publicKeyIdHost = this.punyHost(x.publicKey.id);
if (publicKeyIdHost !== expectHost) {
throw new Error('invalid Actor: publicKey.id has different host');
}
Expand Down Expand Up @@ -252,7 +259,7 @@ export class ApPersonService implements OnModuleInit {

this.logger.info(`Creating the Person: ${person.id}`);

const host = this.utilityService.toPuny(new URL(object.id).hostname);
const host = this.punyHost(object.id);

const { fields } = this.analyzeAttachments(person.attachment ?? []);

Expand All @@ -264,8 +271,8 @@ export class ApPersonService implements OnModuleInit {

const url = getOneApHrefNullable(person.url);

if (url && !url.startsWith('https://')) {
throw new Error('unexpected shcema of person url: ' + url);
if (url && !checkHttps(url)) {
throw new Error('unexpected schema of person url: ' + url);
}

// Create user
Expand Down Expand Up @@ -459,8 +466,8 @@ export class ApPersonService implements OnModuleInit {

const url = getOneApHrefNullable(person.url);

if (url && !url.startsWith('https://')) {
throw new Error('unexpected shcema of person url: ' + url);
if (url && !checkHttps(url)) {
throw new Error('unexpected schema of person url: ' + url);
}

const updates = {
Expand Down
4 changes: 4 additions & 0 deletions packages/backend/src/misc/check-https.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export function checkHttps(url: string) {
return url.startsWith('https://') ||
(url.startsWith('http://') && process.env.NODE_ENV !== 'production');
}

0 comments on commit 09764b9

Please sign in to comment.