@geekity/cms 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +162 -49
- package/admin/pages/documents/editor.njk +63 -0
- package/admin/pages/documents/list.njk +2 -0
- package/admin/pages/indieauth/consent.njk +4 -0
- package/admin/pages/settings/privacy.njk +37 -0
- package/admin/pages/users/activity-entry.njk +58 -0
- package/admin/pages/users/activity.njk +66 -0
- package/admin/pages/users/apps.njk +109 -3
- package/dist/admin/documents.d.ts +29 -1
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +88 -6
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/index.d.ts +1 -0
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +1 -0
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/location-field.d.ts +26 -0
- package/dist/admin/location-field.d.ts.map +1 -0
- package/dist/admin/location-field.js +90 -0
- package/dist/admin/location-field.js.map +1 -0
- package/dist/admin/menu.d.ts.map +1 -1
- package/dist/admin/menu.js +5 -1
- package/dist/admin/menu.js.map +1 -1
- package/dist/admin/preview.d.ts.map +1 -1
- package/dist/admin/preview.js +18 -5
- package/dist/admin/preview.js.map +1 -1
- package/dist/admin/read-field.d.ts +23 -0
- package/dist/admin/read-field.d.ts.map +1 -0
- package/dist/admin/read-field.js +53 -0
- package/dist/admin/read-field.js.map +1 -0
- package/dist/admin/routes.d.ts.map +1 -1
- package/dist/admin/routes.js +4 -0
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/settings-page.d.ts +3 -3
- package/dist/admin/settings-page.js +2 -2
- package/dist/admin/settings-pages.d.ts +2 -2
- package/dist/admin/settings-pages.d.ts.map +1 -1
- package/dist/admin/settings-pages.js +4 -2
- package/dist/admin/settings-pages.js.map +1 -1
- package/dist/admin/settings-privacy.d.ts +3 -0
- package/dist/admin/settings-privacy.d.ts.map +1 -0
- package/dist/admin/settings-privacy.js +10 -0
- package/dist/admin/settings-privacy.js.map +1 -0
- package/dist/admin/settings-reading.js +2 -2
- package/dist/admin/settings-reading.js.map +1 -1
- package/dist/admin/settings.d.ts +18 -2
- package/dist/admin/settings.d.ts.map +1 -1
- package/dist/admin/settings.js +27 -0
- package/dist/admin/settings.js.map +1 -1
- package/dist/admin/templates.d.ts +3 -0
- package/dist/admin/templates.d.ts.map +1 -1
- package/dist/admin/templates.js +3 -0
- package/dist/admin/templates.js.map +1 -1
- package/dist/admin/uploads.d.ts.map +1 -1
- package/dist/admin/uploads.js +14 -1
- package/dist/admin/uploads.js.map +1 -1
- package/dist/admin/users.d.ts +8 -0
- package/dist/admin/users.d.ts.map +1 -1
- package/dist/admin/users.js +8 -0
- package/dist/admin/users.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +34 -0
- package/dist/cli.js.map +1 -1
- package/dist/comments/routes.js +2 -2
- package/dist/comments/routes.js.map +1 -1
- package/dist/contact/routes.js +2 -2
- package/dist/contact/routes.js.map +1 -1
- package/dist/content/location.d.ts +58 -0
- package/dist/content/location.d.ts.map +1 -0
- package/dist/content/location.js +208 -0
- package/dist/content/location.js.map +1 -0
- package/dist/content/locations.d.ts +9 -0
- package/dist/content/locations.d.ts.map +1 -0
- package/dist/content/locations.js +82 -0
- package/dist/content/locations.js.map +1 -0
- package/dist/content/metadata/gif.d.ts +3 -0
- package/dist/content/metadata/gif.d.ts.map +1 -0
- package/dist/content/metadata/gif.js +65 -0
- package/dist/content/metadata/gif.js.map +1 -0
- package/dist/content/metadata/index.d.ts +6 -0
- package/dist/content/metadata/index.d.ts.map +1 -0
- package/dist/content/metadata/index.js +24 -0
- package/dist/content/metadata/index.js.map +1 -0
- package/dist/content/metadata/isobmff.d.ts +22 -0
- package/dist/content/metadata/isobmff.d.ts.map +1 -0
- package/dist/content/metadata/isobmff.js +215 -0
- package/dist/content/metadata/isobmff.js.map +1 -0
- package/dist/content/metadata/jpeg.d.ts +3 -0
- package/dist/content/metadata/jpeg.d.ts.map +1 -0
- package/dist/content/metadata/jpeg.js +117 -0
- package/dist/content/metadata/jpeg.js.map +1 -0
- package/dist/content/metadata/png.d.ts +3 -0
- package/dist/content/metadata/png.d.ts.map +1 -0
- package/dist/content/metadata/png.js +74 -0
- package/dist/content/metadata/png.js.map +1 -0
- package/dist/content/metadata/shared.d.ts +17 -0
- package/dist/content/metadata/shared.d.ts.map +1 -0
- package/dist/content/metadata/shared.js +42 -0
- package/dist/content/metadata/shared.js.map +1 -0
- package/dist/content/metadata/sweep.d.ts +14 -0
- package/dist/content/metadata/sweep.d.ts.map +1 -0
- package/dist/content/metadata/sweep.js +54 -0
- package/dist/content/metadata/sweep.js.map +1 -0
- package/dist/content/metadata/tiff.d.ts +7 -0
- package/dist/content/metadata/tiff.d.ts.map +1 -0
- package/dist/content/metadata/tiff.js +56 -0
- package/dist/content/metadata/tiff.js.map +1 -0
- package/dist/content/metadata/webp.d.ts +3 -0
- package/dist/content/metadata/webp.d.ts.map +1 -0
- package/dist/content/metadata/webp.js +67 -0
- package/dist/content/metadata/webp.js.map +1 -0
- package/dist/content/post-type.d.ts +4 -2
- package/dist/content/post-type.d.ts.map +1 -1
- package/dist/content/post-type.js +9 -1
- package/dist/content/post-type.js.map +1 -1
- package/dist/content/read.d.ts +22 -0
- package/dist/content/read.d.ts.map +1 -0
- package/dist/content/read.js +67 -0
- package/dist/content/read.js.map +1 -0
- package/dist/content/store.d.ts +4 -4
- package/dist/content/store.d.ts.map +1 -1
- package/dist/content/store.js +19 -39
- package/dist/content/store.js.map +1 -1
- package/dist/content/sync.d.ts.map +1 -1
- package/dist/content/sync.js +3 -13
- package/dist/content/sync.js.map +1 -1
- package/dist/content/visibility.d.ts +11 -0
- package/dist/content/visibility.d.ts.map +1 -0
- package/dist/content/visibility.js +14 -0
- package/dist/content/visibility.js.map +1 -0
- package/dist/env.d.ts +7 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/federation/article.d.ts.map +1 -1
- package/dist/federation/article.js +41 -14
- package/dist/federation/article.js.map +1 -1
- package/dist/federation/delivery.d.ts +3 -1
- package/dist/federation/delivery.d.ts.map +1 -1
- package/dist/federation/delivery.js +6 -5
- package/dist/federation/delivery.js.map +1 -1
- package/dist/federation/mount.d.ts.map +1 -1
- package/dist/federation/mount.js +3 -1
- package/dist/federation/mount.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/indexnow.js +2 -2
- package/dist/indexnow.js.map +1 -1
- package/dist/indieauth/activity-log.d.ts +114 -0
- package/dist/indieauth/activity-log.d.ts.map +1 -0
- package/dist/indieauth/activity-log.js +335 -0
- package/dist/indieauth/activity-log.js.map +1 -0
- package/dist/indieauth/app-activity.d.ts +14 -0
- package/dist/indieauth/app-activity.d.ts.map +1 -0
- package/dist/indieauth/app-activity.js +110 -0
- package/dist/indieauth/app-activity.js.map +1 -0
- package/dist/indieauth/bearer.d.ts.map +1 -1
- package/dist/indieauth/bearer.js +20 -18
- package/dist/indieauth/bearer.js.map +1 -1
- package/dist/indieauth/client-id.d.ts +10 -0
- package/dist/indieauth/client-id.d.ts.map +1 -0
- package/dist/indieauth/client-id.js +30 -0
- package/dist/indieauth/client-id.js.map +1 -0
- package/dist/indieauth/connected-apps.d.ts +4 -0
- package/dist/indieauth/connected-apps.d.ts.map +1 -1
- package/dist/indieauth/connected-apps.js +149 -20
- package/dist/indieauth/connected-apps.js.map +1 -1
- package/dist/indieauth/consent.d.ts.map +1 -1
- package/dist/indieauth/consent.js +10 -3
- package/dist/indieauth/consent.js.map +1 -1
- package/dist/indieauth/discovery.d.ts +4 -3
- package/dist/indieauth/discovery.d.ts.map +1 -1
- package/dist/indieauth/discovery.js +7 -3
- package/dist/indieauth/discovery.js.map +1 -1
- package/dist/indieauth/grants.d.ts +2 -7
- package/dist/indieauth/grants.d.ts.map +1 -1
- package/dist/indieauth/grants.js.map +1 -1
- package/dist/indieauth/redeem.d.ts.map +1 -1
- package/dist/indieauth/redeem.js +10 -5
- package/dist/indieauth/redeem.js.map +1 -1
- package/dist/indieauth/request.d.ts +8 -4
- package/dist/indieauth/request.d.ts.map +1 -1
- package/dist/indieauth/request.js +29 -30
- package/dist/indieauth/request.js.map +1 -1
- package/dist/indieauth/token.d.ts.map +1 -1
- package/dist/indieauth/token.js +4 -2
- package/dist/indieauth/token.js.map +1 -1
- package/dist/indieauth/tokens.d.ts +28 -7
- package/dist/indieauth/tokens.d.ts.map +1 -1
- package/dist/indieauth/tokens.js +26 -5
- package/dist/indieauth/tokens.js.map +1 -1
- package/dist/micropub/create.d.ts +22 -0
- package/dist/micropub/create.d.ts.map +1 -1
- package/dist/micropub/create.js +107 -8
- package/dist/micropub/create.js.map +1 -1
- package/dist/micropub/endpoint.d.ts.map +1 -1
- package/dist/micropub/endpoint.js +74 -22
- package/dist/micropub/endpoint.js.map +1 -1
- package/dist/micropub/media.d.ts +4 -2
- package/dist/micropub/media.d.ts.map +1 -1
- package/dist/micropub/media.js +43 -38
- package/dist/micropub/media.js.map +1 -1
- package/dist/micropub/update.d.ts +6 -2
- package/dist/micropub/update.d.ts.map +1 -1
- package/dist/micropub/update.js +31 -3
- package/dist/micropub/update.js.map +1 -1
- package/dist/notify.d.ts.map +1 -1
- package/dist/notify.js +2 -5
- package/dist/notify.js.map +1 -1
- package/dist/web/absolute-urls.d.ts +2 -0
- package/dist/web/absolute-urls.d.ts.map +1 -0
- package/dist/web/absolute-urls.js +22 -0
- package/dist/web/absolute-urls.js.map +1 -0
- package/dist/web/context.d.ts +29 -1
- package/dist/web/context.d.ts.map +1 -1
- package/dist/web/context.js +33 -0
- package/dist/web/context.js.map +1 -1
- package/dist/web/conversation.d.ts.map +1 -1
- package/dist/web/conversation.js +5 -4
- package/dist/web/conversation.js.map +1 -1
- package/dist/web/documents.d.ts +19 -10
- package/dist/web/documents.d.ts.map +1 -1
- package/dist/web/documents.js +28 -13
- package/dist/web/documents.js.map +1 -1
- package/dist/web/feed-item.d.ts +25 -6
- package/dist/web/feed-item.d.ts.map +1 -1
- package/dist/web/feed-item.js +31 -7
- package/dist/web/feed-item.js.map +1 -1
- package/dist/web/feed-json.d.ts +3 -1
- package/dist/web/feed-json.d.ts.map +1 -1
- package/dist/web/feed-json.js +2 -0
- package/dist/web/feed-json.js.map +1 -1
- package/dist/web/feed-source.d.ts +6 -0
- package/dist/web/feed-source.d.ts.map +1 -1
- package/dist/web/feed-source.js.map +1 -1
- package/dist/web/feeds.d.ts.map +1 -1
- package/dist/web/feeds.js +2 -0
- package/dist/web/feeds.js.map +1 -1
- package/dist/web/html-attributes.d.ts +3 -0
- package/dist/web/html-attributes.d.ts.map +1 -0
- package/dist/web/html-attributes.js +15 -0
- package/dist/web/html-attributes.js.map +1 -0
- package/dist/web/index.d.ts +1 -1
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +1 -1
- package/dist/web/index.js.map +1 -1
- package/dist/web/negotiate.d.ts +2 -0
- package/dist/web/negotiate.d.ts.map +1 -1
- package/dist/web/negotiate.js +2 -1
- package/dist/web/negotiate.js.map +1 -1
- package/dist/web/render.d.ts +8 -0
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +5 -1
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +14 -10
- package/dist/web/routes.js.map +1 -1
- package/dist/webmention/service.d.ts.map +1 -1
- package/dist/webmention/service.js +7 -2
- package/dist/webmention/service.js.map +1 -1
- package/package.json +1 -1
- package/themes/default/README.md +15 -0
- package/themes/default/layouts/base.njk +2 -0
- package/themes/default/layouts/post.njk +7 -1
- package/themes/default/partials/location.njk +12 -0
- package/themes/default/partials/post-list.njk +2 -0
- package/themes/default/partials/read.njk +5 -0
package/dist/indexnow.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readSiteSettings } from './admin/settings.js';
|
|
2
2
|
import { isPrivateHost } from './webmention/public-address.js';
|
|
3
|
-
import {
|
|
3
|
+
import { isListed } from './web/documents.js';
|
|
4
4
|
import { indexNowKeyPath } from './web/indexnow.js';
|
|
5
5
|
import { absoluteUrl } from './web/negotiate.js';
|
|
6
6
|
/** The shared endpoint: a submission here reaches every IndexNow engine. */
|
|
@@ -128,7 +128,7 @@ export function createIndexNowNotifier(options) {
|
|
|
128
128
|
}
|
|
129
129
|
/** The document's absolute URL while the public site shows it, and `undefined` otherwise. */
|
|
130
130
|
function publicUrl(document, now, baseUrl) {
|
|
131
|
-
if (document === undefined || !
|
|
131
|
+
if (document === undefined || !isListed(document, now))
|
|
132
132
|
return undefined;
|
|
133
133
|
return absoluteUrl(document.permalink, baseUrl);
|
|
134
134
|
}
|
package/dist/indexnow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexnow.js","sourceRoot":"","sources":["../src/indexnow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAIvD,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"indexnow.js","sourceRoot":"","sources":["../src/indexnow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { Context, MiddlewareHandler } from 'hono';
|
|
2
|
+
import type { GeekityEnv } from '../env.ts';
|
|
3
|
+
import type { Bearer } from './bearer.ts';
|
|
4
|
+
/** The log, relative to `dataDir`. */
|
|
5
|
+
export declare const ACTIVITY_LOG_FILE = "indieauth-activity.json";
|
|
6
|
+
/** Readable and writable by the site's own user only, like the tokens beside it. */
|
|
7
|
+
export declare const ACTIVITY_LOG_MODE = 384;
|
|
8
|
+
/** How many entries are kept, newest first. */
|
|
9
|
+
export declare const ACTIVITY_LOG_LIMIT = 100;
|
|
10
|
+
/** How long an entry is kept: fourteen days. */
|
|
11
|
+
export declare const ACTIVITY_LOG_MAX_AGE_MS: number;
|
|
12
|
+
/** One field a request carried, as the log keeps it. */
|
|
13
|
+
export type CarriedField = {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly value: string;
|
|
16
|
+
} | {
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly file: {
|
|
19
|
+
readonly filename: string;
|
|
20
|
+
readonly type: string;
|
|
21
|
+
readonly size: number;
|
|
22
|
+
};
|
|
23
|
+
} | {
|
|
24
|
+
readonly name: string;
|
|
25
|
+
readonly redacted: true;
|
|
26
|
+
};
|
|
27
|
+
/** Which endpoint a request went to. */
|
|
28
|
+
export type ActivityEndpoint = 'authorization' | 'token' | 'micropub' | 'media';
|
|
29
|
+
/** What a request's own route knows about it. */
|
|
30
|
+
interface Facts {
|
|
31
|
+
/** The client's URL, when the request named one or its token did. */
|
|
32
|
+
readonly clientId?: string | undefined;
|
|
33
|
+
/** The username the request acted as, when that is known. */
|
|
34
|
+
readonly user?: string | undefined;
|
|
35
|
+
readonly carried: readonly CarriedField[];
|
|
36
|
+
}
|
|
37
|
+
/** An entry's endpoint-specific part, one variant per endpoint and action. */
|
|
38
|
+
export type EndpointFacts = Facts & ({
|
|
39
|
+
readonly endpoint: 'authorization';
|
|
40
|
+
readonly action: 'request';
|
|
41
|
+
/** Whether the request carried an S256 `code_challenge`. */
|
|
42
|
+
readonly pkce: boolean;
|
|
43
|
+
readonly allowedWithoutPkce?: true;
|
|
44
|
+
/** The scopes asked for, as asked, offered or not. */
|
|
45
|
+
readonly scopes: readonly string[];
|
|
46
|
+
} | {
|
|
47
|
+
readonly endpoint: 'authorization';
|
|
48
|
+
readonly action: 'redeem';
|
|
49
|
+
} | {
|
|
50
|
+
readonly endpoint: 'token';
|
|
51
|
+
/** The `grant_type`, `authorization_code` when the client left it out. */
|
|
52
|
+
readonly action: string;
|
|
53
|
+
/** The scopes the token was issued with, on success. */
|
|
54
|
+
readonly scopes: readonly string[];
|
|
55
|
+
} | {
|
|
56
|
+
readonly endpoint: 'micropub' | 'media';
|
|
57
|
+
/** The POST's action (`create` when none), `upload`, or the GET's `q=…`. */
|
|
58
|
+
readonly action: string;
|
|
59
|
+
});
|
|
60
|
+
/** One request, as the log keeps it. */
|
|
61
|
+
export type ActivityEntry = EndpointFacts & {
|
|
62
|
+
readonly id: string;
|
|
63
|
+
/** When it arrived, as an ISO instant. */
|
|
64
|
+
readonly at: string;
|
|
65
|
+
readonly method: string;
|
|
66
|
+
readonly status: number;
|
|
67
|
+
/** The error code it was refused with. */
|
|
68
|
+
readonly error?: string | undefined;
|
|
69
|
+
readonly errorDescription?: string | undefined;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* What a handler adds to its entry that the response cannot show: a refusal
|
|
73
|
+
* answered with an HTML page, and the user and scopes a token was issued for.
|
|
74
|
+
*/
|
|
75
|
+
export interface ActivityNote {
|
|
76
|
+
readonly user?: string;
|
|
77
|
+
readonly scopes?: readonly string[];
|
|
78
|
+
readonly refusal?: {
|
|
79
|
+
readonly error: string;
|
|
80
|
+
readonly description: string;
|
|
81
|
+
};
|
|
82
|
+
readonly allowedWithoutPkce?: true;
|
|
83
|
+
}
|
|
84
|
+
/** Add to what this request's entry will say. */
|
|
85
|
+
export declare function noteActivity(c: Context<GeekityEnv>, note: ActivityNote): void;
|
|
86
|
+
/** Whether an entry is a failure: refused with an error, or answered with an error status. */
|
|
87
|
+
export declare function isFailure(entry: ActivityEntry): boolean;
|
|
88
|
+
/** Whether an entry is still inside the age limit at `now`. */
|
|
89
|
+
export declare function isFresh(entry: ActivityEntry, now: Date): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Every entry, newest first. Read in the file's queue, so a read follows the
|
|
92
|
+
* writes queued before it and a screen shows the request that just finished.
|
|
93
|
+
*/
|
|
94
|
+
export declare function readActivityLog(dataDir: string): Promise<ActivityEntry[]>;
|
|
95
|
+
/** Settles once every entry already on its way to the file has landed, so closing never leaves one half written. */
|
|
96
|
+
export declare function activityLogSettled(dataDir: string): Promise<void>;
|
|
97
|
+
/** What a recording middleware may find on the context: a bearer, once the guard let it in. */
|
|
98
|
+
interface ActivityEnv {
|
|
99
|
+
Variables: GeekityEnv['Variables'] & {
|
|
100
|
+
bearer?: Bearer;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/** The authorization request, as the consent screen received it. */
|
|
104
|
+
export declare const logAuthorizationRequest: MiddlewareHandler<ActivityEnv>;
|
|
105
|
+
/** A client redeeming its code at the authorization endpoint for the profile. */
|
|
106
|
+
export declare const logAuthorizationRedemption: MiddlewareHandler<ActivityEnv>;
|
|
107
|
+
/** A client redeeming a code or a refresh token at the token endpoint. */
|
|
108
|
+
export declare const logTokenRequest: MiddlewareHandler<ActivityEnv>;
|
|
109
|
+
/** A query, or a create, update, delete or undelete, at the Micropub endpoint. */
|
|
110
|
+
export declare const logMicropubRequest: MiddlewareHandler<ActivityEnv>;
|
|
111
|
+
/** An upload, or `q=last`, at the media endpoint. */
|
|
112
|
+
export declare const logMediaRequest: MiddlewareHandler<ActivityEnv>;
|
|
113
|
+
export {};
|
|
114
|
+
//# sourceMappingURL=activity-log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity-log.d.ts","sourceRoot":"","sources":["../../src/indieauth/activity-log.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAGvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,sCAAsC;AACtC,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAE3D,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,MAAQ,CAAC;AAEvC,+CAA+C;AAC/C,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,gDAAgD;AAChD,eAAO,MAAM,uBAAuB,QAA2B,CAAC;AAmBhE,wDAAwD;AACxD,MAAM,MAAM,YAAY,GACpB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjD;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5F,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAA;CAAE,CAAC;AAEvD,wCAAwC;AACxC,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;AAEhF,iDAAiD;AACjD,UAAU,KAAK;IACb,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;CAC3C;AAED,8EAA8E;AAC9E,MAAM,MAAM,aAAa,GAAG,KAAK,GAC/B,CACI;IACE,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,IAAI,CAAC;IACnC,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC,GACD;IAAE,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,GACjE;IACE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC,GACD;IACE,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC;IACxC,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CACJ,CAAC;AAEJ,wCAAwC;AACxC,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG;IAC1C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChD,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,QAAQ,CAAC,kBAAkB,CAAC,EAAE,IAAI,CAAC;CACpC;AAED,iDAAiD;AACjD,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAE7E;AAED,8FAA8F;AAC9F,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAEvD;AAED,+DAA+D;AAC/D,wBAAgB,OAAO,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAEhE;AAgBD;;;GAGG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAG/E;AAED,oHAAoH;AACpH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvE;AAcD,+FAA+F;AAC/F,UAAU,WAAW;IACnB,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1D;AA6JD,oEAAoE;AACpE,eAAO,MAAM,uBAAuB,gCAmBlC,CAAC;AAEH,iFAAiF;AACjF,eAAO,MAAM,0BAA0B,gCAUrC,CAAC;AAEH,0EAA0E;AAC1E,eAAO,MAAM,eAAe,gCAW1B,CAAC;AAYH,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,gCAyB7B,CAAC;AAEH,qDAAqD;AACrD,eAAO,MAAM,eAAe,gCAiB1B,CAAC"}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A short log of what apps sent to the IndieAuth and Micropub endpoints, and
|
|
3
|
+
* what they were answered (TASK-221), so a site owner can see why a client
|
|
4
|
+
* failed to sign in or to post without reading the client's source.
|
|
5
|
+
*
|
|
6
|
+
* One entry per request to the authorization endpoint (the request as it
|
|
7
|
+
* reaches the consent screen, and the profile redemption), the token
|
|
8
|
+
* endpoint, Micropub and its media endpoint. Each route records through one
|
|
9
|
+
* middleware placed in front of it, which sees the final status and reads the
|
|
10
|
+
* refusal out of the response itself: Micropub's and OAuth's JSON error
|
|
11
|
+
* bodies, or the `error` on an authorization redirect. A handler adds only
|
|
12
|
+
* what its response does not show, through {@link noteActivity}.
|
|
13
|
+
*
|
|
14
|
+
* Nothing secret is kept. No header is read, so no `Authorization` and no
|
|
15
|
+
* cookie; a field named in {@link SECRET_FIELDS} is kept as its name alone,
|
|
16
|
+
* at any depth of a JSON body; a file part is its name, type and size; and
|
|
17
|
+
* every value is cut short. No client address is stored.
|
|
18
|
+
*
|
|
19
|
+
* The file is bounded by count and by age, private to the site's user, and
|
|
20
|
+
* written after the response is decided without the response waiting on it:
|
|
21
|
+
* a write that fails is a warning on the console, never a different answer.
|
|
22
|
+
*/
|
|
23
|
+
import { randomUUID } from 'node:crypto';
|
|
24
|
+
import path from 'node:path';
|
|
25
|
+
import { findUserById } from '../admin/accounts.js';
|
|
26
|
+
import { readFileIfPresentSync, updateFileAtomically, withFileLock } from '../files/atomic.js';
|
|
27
|
+
/** The log, relative to `dataDir`. */
|
|
28
|
+
export const ACTIVITY_LOG_FILE = 'indieauth-activity.json';
|
|
29
|
+
/** Readable and writable by the site's own user only, like the tokens beside it. */
|
|
30
|
+
export const ACTIVITY_LOG_MODE = 0o600;
|
|
31
|
+
/** How many entries are kept, newest first. */
|
|
32
|
+
export const ACTIVITY_LOG_LIMIT = 100;
|
|
33
|
+
/** How long an entry is kept: fourteen days. */
|
|
34
|
+
export const ACTIVITY_LOG_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1000;
|
|
35
|
+
/** The longest value kept, in characters, before it is cut and marked with an ellipsis. */
|
|
36
|
+
const VALUE_LIMIT = 100;
|
|
37
|
+
/** The most fields one entry lists. */
|
|
38
|
+
const CARRIED_LIMIT = 40;
|
|
39
|
+
/** Fields whose value is never kept, only that they were sent. */
|
|
40
|
+
const SECRET_FIELDS = new Set([
|
|
41
|
+
'access_token',
|
|
42
|
+
'refresh_token',
|
|
43
|
+
'code',
|
|
44
|
+
'code_verifier',
|
|
45
|
+
'client_secret',
|
|
46
|
+
'password',
|
|
47
|
+
'cookie',
|
|
48
|
+
]);
|
|
49
|
+
/** Add to what this request's entry will say. */
|
|
50
|
+
export function noteActivity(c, note) {
|
|
51
|
+
c.set('activityNote', { ...c.var.activityNote, ...note });
|
|
52
|
+
}
|
|
53
|
+
/** Whether an entry is a failure: refused with an error, or answered with an error status. */
|
|
54
|
+
export function isFailure(entry) {
|
|
55
|
+
return entry.error !== undefined || entry.status >= 400;
|
|
56
|
+
}
|
|
57
|
+
/** Whether an entry is still inside the age limit at `now`. */
|
|
58
|
+
export function isFresh(entry, now) {
|
|
59
|
+
return now.getTime() - Date.parse(entry.at) <= ACTIVITY_LOG_MAX_AGE_MS;
|
|
60
|
+
}
|
|
61
|
+
function logFile(dataDir) {
|
|
62
|
+
return path.join(dataDir, ACTIVITY_LOG_FILE);
|
|
63
|
+
}
|
|
64
|
+
function parseLog(text) {
|
|
65
|
+
if (text === undefined)
|
|
66
|
+
return [];
|
|
67
|
+
try {
|
|
68
|
+
const parsed = JSON.parse(text);
|
|
69
|
+
return Array.isArray(parsed.entries) ? parsed.entries : [];
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Every entry, newest first. Read in the file's queue, so a read follows the
|
|
77
|
+
* writes queued before it and a screen shows the request that just finished.
|
|
78
|
+
*/
|
|
79
|
+
export async function readActivityLog(dataDir) {
|
|
80
|
+
const file = logFile(dataDir);
|
|
81
|
+
return await withFileLock(file, () => parseLog(readFileIfPresentSync(file)));
|
|
82
|
+
}
|
|
83
|
+
/** Settles once every entry already on its way to the file has landed, so closing never leaves one half written. */
|
|
84
|
+
export async function activityLogSettled(dataDir) {
|
|
85
|
+
await withFileLock(logFile(dataDir), () => undefined);
|
|
86
|
+
}
|
|
87
|
+
async function appendEntry(dataDir, entry, now) {
|
|
88
|
+
await updateFileAtomically(logFile(dataDir), (current) => {
|
|
89
|
+
const kept = parseLog(current).filter((old) => isFresh(old, now));
|
|
90
|
+
const entries = [entry, ...kept].slice(0, ACTIVITY_LOG_LIMIT);
|
|
91
|
+
return `${JSON.stringify({ entries }, null, 2)}\n`;
|
|
92
|
+
}, { mode: ACTIVITY_LOG_MODE });
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The middleware that records one entry per request to a route, after the
|
|
96
|
+
* route has answered. A failure to describe or to write is a warning; the
|
|
97
|
+
* write is not awaited, so the response never waits on the disk.
|
|
98
|
+
*/
|
|
99
|
+
function recordActivity(describe) {
|
|
100
|
+
return async (c, next) => {
|
|
101
|
+
await next();
|
|
102
|
+
const { dataDir, now } = c.var.config;
|
|
103
|
+
try {
|
|
104
|
+
const facts = await describe(c);
|
|
105
|
+
const refusal = c.var.activityNote?.refusal ?? (await refusalIn(c.res));
|
|
106
|
+
const at = now();
|
|
107
|
+
const entry = {
|
|
108
|
+
id: randomUUID(),
|
|
109
|
+
at: at.toISOString(),
|
|
110
|
+
method: c.req.method,
|
|
111
|
+
status: c.res.status,
|
|
112
|
+
...facts,
|
|
113
|
+
error: refusal?.error,
|
|
114
|
+
errorDescription: refusal?.description,
|
|
115
|
+
};
|
|
116
|
+
appendEntry(dataDir, entry, at).catch((error) => {
|
|
117
|
+
warn(error);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
warn(error);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function warn(error) {
|
|
126
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
127
|
+
console.warn(`Could not write the IndieAuth and Micropub activity log: ${reason}`);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The OAuth or Micropub error a response carries: in a JSON error body, or in
|
|
131
|
+
* the query of a redirect back to the client. Only those two fields are read.
|
|
132
|
+
*/
|
|
133
|
+
async function refusalIn(response) {
|
|
134
|
+
const location = response.headers.get('location');
|
|
135
|
+
if (location !== null) {
|
|
136
|
+
const query = URL.parse(location, 'http://localhost/')?.searchParams;
|
|
137
|
+
const error = query?.get('error');
|
|
138
|
+
if (error != null)
|
|
139
|
+
return { error, description: query?.get('error_description') ?? undefined };
|
|
140
|
+
}
|
|
141
|
+
const type = response.headers.get('content-type') ?? '';
|
|
142
|
+
if (response.status < 400 || !/^application\/json\b/i.test(type))
|
|
143
|
+
return undefined;
|
|
144
|
+
const body = (await response.clone().json());
|
|
145
|
+
const error = body['error'];
|
|
146
|
+
const description = body['error_description'];
|
|
147
|
+
if (typeof error !== 'string')
|
|
148
|
+
return undefined;
|
|
149
|
+
return { error, description: typeof description === 'string' ? description : undefined };
|
|
150
|
+
}
|
|
151
|
+
/** `value`, cut to {@link VALUE_LIMIT} characters with an ellipsis when it was longer. */
|
|
152
|
+
function short(value) {
|
|
153
|
+
return value.length > VALUE_LIMIT ? `${value.slice(0, VALUE_LIMIT)}…` : value;
|
|
154
|
+
}
|
|
155
|
+
/** A JSON value as one line of text, every secret field inside it replaced. */
|
|
156
|
+
function summary(value) {
|
|
157
|
+
if (typeof value === 'string')
|
|
158
|
+
return value;
|
|
159
|
+
if (Array.isArray(value) && value.every((item) => typeof item === 'string')) {
|
|
160
|
+
return value.join(', ');
|
|
161
|
+
}
|
|
162
|
+
return (JSON.stringify(value, (key, inner) => SECRET_FIELDS.has(key) ? '[not recorded]' : inner) ?? '');
|
|
163
|
+
}
|
|
164
|
+
function field(name, value) {
|
|
165
|
+
if (SECRET_FIELDS.has(name))
|
|
166
|
+
return { name: short(name), redacted: true };
|
|
167
|
+
return { name: short(name), value: short(summary(value)) };
|
|
168
|
+
}
|
|
169
|
+
function fromParams(params, skip = []) {
|
|
170
|
+
return [...params]
|
|
171
|
+
.filter(([name]) => !skip.includes(name))
|
|
172
|
+
.map(([name, value]) => field(name, value))
|
|
173
|
+
.slice(0, CARRIED_LIMIT);
|
|
174
|
+
}
|
|
175
|
+
function fromForm(form) {
|
|
176
|
+
const fields = [];
|
|
177
|
+
for (const [name, value] of form) {
|
|
178
|
+
fields.push(typeof value === 'string' || SECRET_FIELDS.has(name)
|
|
179
|
+
? field(name, value)
|
|
180
|
+
: {
|
|
181
|
+
name: short(name),
|
|
182
|
+
file: { filename: short(value.name), type: short(value.type), size: value.size },
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return fields.slice(0, CARRIED_LIMIT);
|
|
186
|
+
}
|
|
187
|
+
function isRecord(value) {
|
|
188
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
189
|
+
}
|
|
190
|
+
/** A Micropub JSON body's fields: its `properties` one by one, then everything else. */
|
|
191
|
+
function fromJson(body) {
|
|
192
|
+
if (!isRecord(body))
|
|
193
|
+
return [];
|
|
194
|
+
const fields = [];
|
|
195
|
+
for (const [name, value] of Object.entries(body)) {
|
|
196
|
+
if (name === 'properties' && isRecord(value)) {
|
|
197
|
+
for (const [property, values] of Object.entries(value))
|
|
198
|
+
fields.push(field(property, values));
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
fields.push(field(name, value));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return fields.slice(0, CARRIED_LIMIT);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* The body the route already read, never one it left unread: an upload
|
|
208
|
+
* refused for its size before anything touched it stays untouched.
|
|
209
|
+
*/
|
|
210
|
+
async function readBody(c) {
|
|
211
|
+
if (Object.keys(c.req.bodyCache).length === 0)
|
|
212
|
+
return { kind: 'none' };
|
|
213
|
+
const type = c.req.header('content-type') ?? '';
|
|
214
|
+
if (/^(application\/x-www-form-urlencoded|multipart\/form-data)\b/i.test(type)) {
|
|
215
|
+
try {
|
|
216
|
+
return { kind: 'form', form: await c.req.formData() };
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
return { kind: 'none' };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (/^application\/json\b/i.test(type)) {
|
|
223
|
+
try {
|
|
224
|
+
return { kind: 'json', value: await c.req.json() };
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
return { kind: 'none' };
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return { kind: 'none' };
|
|
231
|
+
}
|
|
232
|
+
/** What the route's form body said `name` was, when it was text. */
|
|
233
|
+
function formText(form, name) {
|
|
234
|
+
const value = form.get(name);
|
|
235
|
+
return typeof value === 'string' ? short(value) : undefined;
|
|
236
|
+
}
|
|
237
|
+
/** The authorization request, as the consent screen received it. */
|
|
238
|
+
export const logAuthorizationRequest = recordActivity((c) => {
|
|
239
|
+
const params = new URL(c.req.url).searchParams;
|
|
240
|
+
const userId = c.var.session?.userId;
|
|
241
|
+
const user = userId == null ? undefined : findUserById(c.var.config.dataDir, userId);
|
|
242
|
+
const clientId = params.get('client_id');
|
|
243
|
+
return Promise.resolve({
|
|
244
|
+
endpoint: 'authorization',
|
|
245
|
+
action: 'request',
|
|
246
|
+
clientId: clientId === null ? undefined : short(clientId),
|
|
247
|
+
user: user?.username,
|
|
248
|
+
pkce: (params.get('code_challenge') ?? '') !== '' && params.get('code_challenge_method') === 'S256',
|
|
249
|
+
...(c.var.activityNote?.allowedWithoutPkce === true ? { allowedWithoutPkce: true } : {}),
|
|
250
|
+
scopes: (params.get('scope') ?? '')
|
|
251
|
+
.split(' ')
|
|
252
|
+
.filter((scope) => scope !== '')
|
|
253
|
+
.map(short),
|
|
254
|
+
carried: fromParams(params),
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
/** A client redeeming its code at the authorization endpoint for the profile. */
|
|
258
|
+
export const logAuthorizationRedemption = recordActivity(async (c) => {
|
|
259
|
+
const body = await readBody(c);
|
|
260
|
+
const form = body.kind === 'form' ? body.form : new FormData();
|
|
261
|
+
return {
|
|
262
|
+
endpoint: 'authorization',
|
|
263
|
+
action: 'redeem',
|
|
264
|
+
clientId: formText(form, 'client_id'),
|
|
265
|
+
user: c.var.activityNote?.user,
|
|
266
|
+
carried: fromForm(form),
|
|
267
|
+
};
|
|
268
|
+
});
|
|
269
|
+
/** A client redeeming a code or a refresh token at the token endpoint. */
|
|
270
|
+
export const logTokenRequest = recordActivity(async (c) => {
|
|
271
|
+
const body = await readBody(c);
|
|
272
|
+
const form = body.kind === 'form' ? body.form : new FormData();
|
|
273
|
+
return {
|
|
274
|
+
endpoint: 'token',
|
|
275
|
+
action: formText(form, 'grant_type') ?? 'authorization_code',
|
|
276
|
+
clientId: formText(form, 'client_id'),
|
|
277
|
+
user: c.var.activityNote?.user,
|
|
278
|
+
scopes: c.var.activityNote?.scopes ?? [],
|
|
279
|
+
carried: fromForm(form),
|
|
280
|
+
};
|
|
281
|
+
});
|
|
282
|
+
/** Who a Micropub request acted as, once the bearer guard let it in. */
|
|
283
|
+
function bearerFacts(c) {
|
|
284
|
+
const { bearer } = c.var;
|
|
285
|
+
const token = bearer?.token;
|
|
286
|
+
return {
|
|
287
|
+
clientId: token?.kind === 'created' ? undefined : token?.clientId,
|
|
288
|
+
user: bearer?.user.username,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/** A query, or a create, update, delete or undelete, at the Micropub endpoint. */
|
|
292
|
+
export const logMicropubRequest = recordActivity(async (c) => {
|
|
293
|
+
if (c.req.method === 'GET') {
|
|
294
|
+
const params = new URL(c.req.url).searchParams;
|
|
295
|
+
return {
|
|
296
|
+
endpoint: 'micropub',
|
|
297
|
+
action: short(`q=${params.get('q') ?? ''}`),
|
|
298
|
+
...bearerFacts(c),
|
|
299
|
+
carried: fromParams(params, ['q']),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
const body = await readBody(c);
|
|
303
|
+
const carried = body.kind === 'form' ? fromForm(body.form) : body.kind === 'json' ? fromJson(body.value) : [];
|
|
304
|
+
const named = body.kind === 'form'
|
|
305
|
+
? body.form.get('action')
|
|
306
|
+
: body.kind === 'json' && isRecord(body.value)
|
|
307
|
+
? body.value['action']
|
|
308
|
+
: undefined;
|
|
309
|
+
return {
|
|
310
|
+
endpoint: 'micropub',
|
|
311
|
+
action: typeof named === 'string' ? short(named) : 'create',
|
|
312
|
+
...bearerFacts(c),
|
|
313
|
+
carried,
|
|
314
|
+
};
|
|
315
|
+
});
|
|
316
|
+
/** An upload, or `q=last`, at the media endpoint. */
|
|
317
|
+
export const logMediaRequest = recordActivity(async (c) => {
|
|
318
|
+
if (c.req.method === 'GET') {
|
|
319
|
+
const params = new URL(c.req.url).searchParams;
|
|
320
|
+
return {
|
|
321
|
+
endpoint: 'media',
|
|
322
|
+
action: short(`q=${params.get('q') ?? ''}`),
|
|
323
|
+
...bearerFacts(c),
|
|
324
|
+
carried: fromParams(params, ['q']),
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
const body = await readBody(c);
|
|
328
|
+
return {
|
|
329
|
+
endpoint: 'media',
|
|
330
|
+
action: 'upload',
|
|
331
|
+
...bearerFacts(c),
|
|
332
|
+
carried: body.kind === 'form' ? fromForm(body.form) : [],
|
|
333
|
+
};
|
|
334
|
+
});
|
|
335
|
+
//# sourceMappingURL=activity-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity-log.js","sourceRoot":"","sources":["../../src/indieauth/activity-log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Users > App activity (TASK-221): the recent requests apps made to the
|
|
3
|
+
* IndieAuth and Micropub endpoints, newest first, failures marked, and one
|
|
4
|
+
* request in full. Where a site owner looks when an app will not sign in or
|
|
5
|
+
* post. Any signed-in admin may read it, as with the other admin screens.
|
|
6
|
+
*/
|
|
7
|
+
import type { Hono } from 'hono';
|
|
8
|
+
import type { AdminRender } from '../admin/documents.ts';
|
|
9
|
+
import type { GeekityEnv } from '../env.ts';
|
|
10
|
+
/** Register the list and the screen for one entry. */
|
|
11
|
+
export declare function mountAppActivity(app: Hono<GeekityEnv>, options: {
|
|
12
|
+
render: AdminRender;
|
|
13
|
+
}): void;
|
|
14
|
+
//# sourceMappingURL=app-activity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-activity.d.ts","sourceRoot":"","sources":["../../src/indieauth/app-activity.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAKzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAe5C,sDAAsD;AACtD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GAAG,IAAI,CAwC9F"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { formatInTimezone } from '../admin/formatting.js';
|
|
2
|
+
import { readSiteSettings } from '../admin/settings.js';
|
|
3
|
+
import { ADMIN_TEMPLATES } from '../admin/templates.js';
|
|
4
|
+
import { APP_ACTIVITY_CHILD, APP_ACTIVITY_PATH } from '../admin/users.js';
|
|
5
|
+
import { isFailure, isFresh, readActivityLog } from './activity-log.js';
|
|
6
|
+
/** What each endpoint is called on the screen. */
|
|
7
|
+
const ENDPOINT_LABELS = {
|
|
8
|
+
authorization: 'Authorization',
|
|
9
|
+
token: 'Token',
|
|
10
|
+
micropub: 'Micropub',
|
|
11
|
+
media: 'Media',
|
|
12
|
+
};
|
|
13
|
+
/** The query that narrows the list to failures. */
|
|
14
|
+
const FAILURES_QUERY = 'show=failures';
|
|
15
|
+
/** Register the list and the screen for one entry. */
|
|
16
|
+
export function mountAppActivity(app, options) {
|
|
17
|
+
const { render } = options;
|
|
18
|
+
app.get(APP_ACTIVITY_PATH, async (c) => {
|
|
19
|
+
const { config } = c.var;
|
|
20
|
+
const timezone = readSiteSettings(config.contentDir).timezone;
|
|
21
|
+
const entries = await freshEntries(config.dataDir, config.now());
|
|
22
|
+
const failuresOnly = c.req.query('show') === 'failures';
|
|
23
|
+
const failures = entries.filter(isFailure);
|
|
24
|
+
return render(c, ADMIN_TEMPLATES.appActivity, {
|
|
25
|
+
section: 'users',
|
|
26
|
+
child: APP_ACTIVITY_CHILD,
|
|
27
|
+
tabs: [
|
|
28
|
+
{ label: 'All', url: APP_ACTIVITY_PATH, count: entries.length, current: !failuresOnly },
|
|
29
|
+
{
|
|
30
|
+
label: 'Failures',
|
|
31
|
+
url: `${APP_ACTIVITY_PATH}?${FAILURES_QUERY}`,
|
|
32
|
+
count: failures.length,
|
|
33
|
+
current: failuresOnly,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
rows: (failuresOnly ? failures : entries).map((entry) => row(entry, timezone)),
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
app.get(`${APP_ACTIVITY_PATH}/:id`, async (c) => {
|
|
40
|
+
const { config } = c.var;
|
|
41
|
+
const entries = await freshEntries(config.dataDir, config.now());
|
|
42
|
+
const entry = entries.find((candidate) => candidate.id === c.req.param('id'));
|
|
43
|
+
if (entry === undefined)
|
|
44
|
+
return c.notFound();
|
|
45
|
+
const timezone = readSiteSettings(config.contentDir).timezone;
|
|
46
|
+
return render(c, ADMIN_TEMPLATES.appActivityEntry, {
|
|
47
|
+
section: 'users',
|
|
48
|
+
child: APP_ACTIVITY_CHILD,
|
|
49
|
+
listUrl: APP_ACTIVITY_PATH,
|
|
50
|
+
entry: row(entry, timezone),
|
|
51
|
+
details: details(entry),
|
|
52
|
+
carried: entry.carried.map(carriedRow),
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async function freshEntries(dataDir, now) {
|
|
57
|
+
return (await readActivityLog(dataDir)).filter((entry) => isFresh(entry, now));
|
|
58
|
+
}
|
|
59
|
+
/** One entry as the list shows it. */
|
|
60
|
+
function row(entry, timezone) {
|
|
61
|
+
const failed = isFailure(entry);
|
|
62
|
+
return {
|
|
63
|
+
url: `${APP_ACTIVITY_PATH}/${entry.id}`,
|
|
64
|
+
when: { iso: entry.at, text: formatInTimezone(entry.at, timezone) },
|
|
65
|
+
endpoint: ENDPOINT_LABELS[entry.endpoint],
|
|
66
|
+
action: entry.action,
|
|
67
|
+
app: entry.clientId,
|
|
68
|
+
user: entry.user,
|
|
69
|
+
status: entry.status,
|
|
70
|
+
failed,
|
|
71
|
+
error: entry.error,
|
|
72
|
+
errorDescription: entry.errorDescription,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** What only the full view shows: the method, and what an endpoint adds of its own. */
|
|
76
|
+
function details(entry) {
|
|
77
|
+
const lines = [{ label: 'Method', value: entry.method }];
|
|
78
|
+
if (entry.endpoint === 'authorization' && entry.action === 'request') {
|
|
79
|
+
lines.push({
|
|
80
|
+
label: 'PKCE',
|
|
81
|
+
value: entry.pkce
|
|
82
|
+
? 'An S256 code_challenge was sent'
|
|
83
|
+
: entry.allowedWithoutPkce === true
|
|
84
|
+
? 'Allowed without PKCE: the app is on your list of apps allowed without PKCE'
|
|
85
|
+
: 'No S256 code_challenge was sent',
|
|
86
|
+
}, { label: 'Scopes asked for', value: listed(entry.scopes) });
|
|
87
|
+
}
|
|
88
|
+
if (entry.endpoint === 'token') {
|
|
89
|
+
lines.push({ label: 'Scopes granted', value: listed(entry.scopes) });
|
|
90
|
+
}
|
|
91
|
+
return lines;
|
|
92
|
+
}
|
|
93
|
+
function listed(values) {
|
|
94
|
+
return values.length === 0 ? 'None' : values.join(' ');
|
|
95
|
+
}
|
|
96
|
+
/** One field the request carried, as its row in the full view says it. */
|
|
97
|
+
function carriedRow(field) {
|
|
98
|
+
if ('file' in field) {
|
|
99
|
+
const { filename, type, size } = field.file;
|
|
100
|
+
return {
|
|
101
|
+
name: field.name,
|
|
102
|
+
value: `${filename} (${type === '' ? 'no type' : type}, ${String(size)} bytes)`,
|
|
103
|
+
note: true,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if ('redacted' in field)
|
|
107
|
+
return { name: field.name, value: 'Sent, not recorded', note: true };
|
|
108
|
+
return { name: field.name, value: field.value, note: false };
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=app-activity.js.map
|