@helyx/module-account-gate 1.0.9 → 1.0.11
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/CHANGELOG.md +17 -0
- package/dist/contracts.d.ts +1 -1
- package/dist/contracts.js +1 -1
- package/dist/index.js +2 -4
- package/dist/records.d.ts +0 -47
- package/dist/records.js +0 -41
- package/manifest.json +1 -1
- package/migrations/0006_remove_legacy_gate_storage.sql +2 -0
- package/migrations/0007_privacy_suppression_trigger_privileges.sql +32 -0
- package/package.json +2 -2
- package/dist/password-resource.d.ts +0 -8
- package/dist/password-resource.js +0 -208
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.11
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Harden dashboard authentication, privacy execution, control routing, database transactions, and self-host configuration.
|
|
8
|
+
|
|
9
|
+
Add bounded multi-value record reads and use them to batch Polls and Reaction Roles dashboard queries. Improve dashboard presentation, Forms workflows, release safety, and operational tooling across hosted and self-hosted deployments.
|
|
10
|
+
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
- @helyx/sdk@0.7.0
|
|
13
|
+
|
|
14
|
+
## 1.0.10
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Launch the shared gaming statistics foundation and the Achievements, Counting and Trivia module integrations, while removing retired Access Control and Counting storage through guarded migrations.
|
|
19
|
+
|
|
3
20
|
## 1.0.9
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/dist/contracts.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export declare const ACCOUNT_GATE_IDENTITY: {
|
|
|
2
2
|
readonly packageName: "@helyx/module-account-gate";
|
|
3
3
|
readonly moduleId: "helyx.account-gate";
|
|
4
4
|
readonly name: "Access Control";
|
|
5
|
-
readonly version: "1.0.
|
|
5
|
+
readonly version: "1.0.11";
|
|
6
6
|
readonly releaseStatus: "live";
|
|
7
7
|
readonly category: "safety";
|
|
8
8
|
readonly icon: "shield-check";
|
package/dist/contracts.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -7,7 +7,6 @@ import { ACCOUNT_GATE_COMPONENTS, ACCOUNT_GATE_IDENTITY, ACCOUNT_GATE_SESSION_PU
|
|
|
7
7
|
import { generatedChallengePool, isStrictModeActive, parseAccountGateConfiguration, validateRuntimeCapabilities, } from "./configuration.js";
|
|
8
8
|
import { applyRoleTransition, neutralKickDirectMessage, } from "./enforcement.js";
|
|
9
9
|
import { verifyPasswordEntry } from "./password-entry.js";
|
|
10
|
-
import { getPasswordSecret } from "./password-resource.js";
|
|
11
10
|
import { accountGateMemberResource } from "./member-resource.js";
|
|
12
11
|
import { accountGateRecords } from "./records.js";
|
|
13
12
|
import { serverQuestionResource } from "./question-resource.js";
|
|
@@ -1037,7 +1036,7 @@ async function handlePasswordEntry(context) {
|
|
|
1037
1036
|
const secret = state.panelId
|
|
1038
1037
|
? ((await getGatePanelRuntime(store, context.serverId, state.panelId))
|
|
1039
1038
|
?.password ?? null)
|
|
1040
|
-
:
|
|
1039
|
+
: null;
|
|
1041
1040
|
const matched = secret !== null &&
|
|
1042
1041
|
(await verifyPasswordEntry(context.content, secret.encodedHash, secret));
|
|
1043
1042
|
await processGatewayAction(context.services, context.serverId, context.userId, session, matched
|
|
@@ -2744,8 +2743,7 @@ export async function validateAccountGateSetup(services, guildId, configuration,
|
|
|
2744
2743
|
!configuration.temporaryRoleIds.every((roleId) => passwordAudience.roles.some((role) => role.roleId === roleId && role.exists && role.canView)))
|
|
2745
2744
|
errors.push("Password Entry requires every configured temporary pre-gate role to view its isolated channel.");
|
|
2746
2745
|
const store = services.get(HELYX_SERVICE_NAMES.records);
|
|
2747
|
-
if (!(await hasPasswordGatePanel(store, guildId))
|
|
2748
|
-
!(await getPasswordSecret(store, guildId)))
|
|
2746
|
+
if (!(await hasPasswordGatePanel(store, guildId)))
|
|
2749
2747
|
errors.push("Password Entry needs a published panel with a password.");
|
|
2750
2748
|
}
|
|
2751
2749
|
if (configuration.enabledChallengeTypes.includes("server_question") &&
|
package/dist/records.d.ts
CHANGED
|
@@ -47,23 +47,6 @@ export declare const accountGateRecords: {
|
|
|
47
47
|
readonly writableFields: readonly ["channel_id", "message_id", "message_body", "access_type", "password_hash", "password_ignore_case", "password_trim_whitespace", "revision", "updated_at"];
|
|
48
48
|
readonly orderKeys: readonly [readonly ["guild_id", "created_at", "panel_id"]];
|
|
49
49
|
};
|
|
50
|
-
readonly public_channels: {
|
|
51
|
-
readonly table: "account_gate_public_channels";
|
|
52
|
-
readonly fields: {
|
|
53
|
-
readonly guild_id: {
|
|
54
|
-
readonly type: "string";
|
|
55
|
-
};
|
|
56
|
-
readonly channel_id: {
|
|
57
|
-
readonly type: "string";
|
|
58
|
-
};
|
|
59
|
-
readonly created_at: {
|
|
60
|
-
readonly type: "date";
|
|
61
|
-
};
|
|
62
|
-
};
|
|
63
|
-
readonly uniqueKeys: readonly [readonly ["guild_id", "channel_id"]];
|
|
64
|
-
readonly readableFields: readonly ["guild_id", "channel_id", "created_at"];
|
|
65
|
-
readonly orderKeys: readonly [readonly ["guild_id", "channel_id"]];
|
|
66
|
-
};
|
|
67
50
|
readonly questions: {
|
|
68
51
|
readonly table: "account_gate_questions";
|
|
69
52
|
readonly fields: {
|
|
@@ -128,36 +111,6 @@ export declare const accountGateRecords: {
|
|
|
128
111
|
readonly readableFields: readonly ["attribution_id", "question_id", "guild_id", "creator_user_id", "created_at"];
|
|
129
112
|
readonly orderKeys: readonly [readonly ["creator_user_id", "created_at", "attribution_id"]];
|
|
130
113
|
};
|
|
131
|
-
readonly password_secrets: {
|
|
132
|
-
readonly table: "account_gate_password_secrets";
|
|
133
|
-
readonly fields: {
|
|
134
|
-
readonly guild_id: {
|
|
135
|
-
readonly type: "string";
|
|
136
|
-
};
|
|
137
|
-
readonly encoded_hash: {
|
|
138
|
-
readonly type: "string";
|
|
139
|
-
};
|
|
140
|
-
readonly ignore_case: {
|
|
141
|
-
readonly type: "boolean";
|
|
142
|
-
};
|
|
143
|
-
readonly trim_whitespace: {
|
|
144
|
-
readonly type: "boolean";
|
|
145
|
-
};
|
|
146
|
-
readonly revision: {
|
|
147
|
-
readonly type: "number";
|
|
148
|
-
};
|
|
149
|
-
readonly created_at: {
|
|
150
|
-
readonly type: "date";
|
|
151
|
-
};
|
|
152
|
-
readonly updated_at: {
|
|
153
|
-
readonly type: "date";
|
|
154
|
-
};
|
|
155
|
-
};
|
|
156
|
-
readonly uniqueKeys: readonly [readonly ["guild_id"]];
|
|
157
|
-
readonly readableFields: readonly ["guild_id", "encoded_hash", "ignore_case", "trim_whitespace", "revision", "created_at", "updated_at"];
|
|
158
|
-
readonly writableFields: readonly ["encoded_hash", "ignore_case", "trim_whitespace", "revision", "updated_at"];
|
|
159
|
-
readonly orderKeys: readonly [readonly ["guild_id"]];
|
|
160
|
-
};
|
|
161
114
|
readonly attempts: {
|
|
162
115
|
readonly table: "account_gate_attempts";
|
|
163
116
|
readonly fields: {
|
package/dist/records.js
CHANGED
|
@@ -43,17 +43,6 @@ export const accountGateRecords = {
|
|
|
43
43
|
],
|
|
44
44
|
orderKeys: [["guild_id", "created_at", "panel_id"]],
|
|
45
45
|
},
|
|
46
|
-
public_channels: {
|
|
47
|
-
table: "account_gate_public_channels",
|
|
48
|
-
fields: {
|
|
49
|
-
guild_id: { type: "string" },
|
|
50
|
-
channel_id: { type: "string" },
|
|
51
|
-
created_at: { type: "date" },
|
|
52
|
-
},
|
|
53
|
-
uniqueKeys: [["guild_id", "channel_id"]],
|
|
54
|
-
readableFields: ["guild_id", "channel_id", "created_at"],
|
|
55
|
-
orderKeys: [["guild_id", "channel_id"]],
|
|
56
|
-
},
|
|
57
46
|
questions: {
|
|
58
47
|
table: "account_gate_questions",
|
|
59
48
|
fields: {
|
|
@@ -113,36 +102,6 @@ export const accountGateRecords = {
|
|
|
113
102
|
],
|
|
114
103
|
orderKeys: [["creator_user_id", "created_at", "attribution_id"]],
|
|
115
104
|
},
|
|
116
|
-
password_secrets: {
|
|
117
|
-
table: "account_gate_password_secrets",
|
|
118
|
-
fields: {
|
|
119
|
-
guild_id: { type: "string" },
|
|
120
|
-
encoded_hash: { type: "string" },
|
|
121
|
-
ignore_case: { type: "boolean" },
|
|
122
|
-
trim_whitespace: { type: "boolean" },
|
|
123
|
-
revision: { type: "number" },
|
|
124
|
-
created_at: { type: "date" },
|
|
125
|
-
updated_at: { type: "date" },
|
|
126
|
-
},
|
|
127
|
-
uniqueKeys: [["guild_id"]],
|
|
128
|
-
readableFields: [
|
|
129
|
-
"guild_id",
|
|
130
|
-
"encoded_hash",
|
|
131
|
-
"ignore_case",
|
|
132
|
-
"trim_whitespace",
|
|
133
|
-
"revision",
|
|
134
|
-
"created_at",
|
|
135
|
-
"updated_at",
|
|
136
|
-
],
|
|
137
|
-
writableFields: [
|
|
138
|
-
"encoded_hash",
|
|
139
|
-
"ignore_case",
|
|
140
|
-
"trim_whitespace",
|
|
141
|
-
"revision",
|
|
142
|
-
"updated_at",
|
|
143
|
-
],
|
|
144
|
-
orderKeys: [["guild_id"]],
|
|
145
|
-
},
|
|
146
105
|
attempts: {
|
|
147
106
|
table: "account_gate_attempts",
|
|
148
107
|
fields: {
|
package/manifest.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"releaseStatus": "live",
|
|
4
4
|
"id": "helyx.account-gate",
|
|
5
5
|
"name": "Access Control",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.11",
|
|
7
7
|
"description": "Require new members to complete configurable Discord interaction checks before gaining access.",
|
|
8
8
|
"entry": "./dist/index.js",
|
|
9
9
|
"framework": "^0.1.0",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
-- Privacy erasure deletes Account Gate subject rows through a deliberately
|
|
2
|
+
-- column-scoped executor role. The deletion triggers must still be able to
|
|
3
|
+
-- write the suppression tombstone that prevents erased data being recreated.
|
|
4
|
+
CREATE OR REPLACE FUNCTION public.account_gate_install_privacy_suppression()
|
|
5
|
+
RETURNS trigger
|
|
6
|
+
LANGUAGE plpgsql
|
|
7
|
+
SECURITY DEFINER
|
|
8
|
+
SET search_path = pg_catalog, public
|
|
9
|
+
AS $$
|
|
10
|
+
BEGIN
|
|
11
|
+
INSERT INTO public.account_gate_privacy_suppressions (
|
|
12
|
+
suppression_id,
|
|
13
|
+
guild_id,
|
|
14
|
+
member_user_id,
|
|
15
|
+
suppressed_at,
|
|
16
|
+
created_at
|
|
17
|
+
)
|
|
18
|
+
VALUES (
|
|
19
|
+
OLD.guild_id || ':' || OLD.member_user_id,
|
|
20
|
+
OLD.guild_id,
|
|
21
|
+
OLD.member_user_id,
|
|
22
|
+
clock_timestamp(),
|
|
23
|
+
clock_timestamp()
|
|
24
|
+
)
|
|
25
|
+
ON CONFLICT (guild_id, member_user_id)
|
|
26
|
+
DO UPDATE SET suppressed_at = GREATEST(
|
|
27
|
+
public.account_gate_privacy_suppressions.suppressed_at,
|
|
28
|
+
EXCLUDED.suppressed_at
|
|
29
|
+
);
|
|
30
|
+
RETURN OLD;
|
|
31
|
+
END;
|
|
32
|
+
$$;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helyx/module-account-gate",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "Require configurable Discord interaction checks before new members gain access.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"helyx",
|
|
@@ -49,6 +49,6 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@helyx/module-manifest": ">=0.6.0 <0.7.0",
|
|
52
|
-
"@helyx/sdk": ">=0.
|
|
52
|
+
"@helyx/sdk": ">=0.7.0 <0.8.0"
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { ModuleManagedResource, ModuleRecordService } from "@helyx/sdk";
|
|
2
|
-
export declare const passwordEntryPhraseResource: ModuleManagedResource;
|
|
3
|
-
export declare function getPasswordSecret(records: ModuleRecordService, guildId: string): Promise<{
|
|
4
|
-
encodedHash: string;
|
|
5
|
-
ignoreCase: boolean;
|
|
6
|
-
trimWhitespace: boolean;
|
|
7
|
-
} | null>;
|
|
8
|
-
//# sourceMappingURL=password-resource.d.ts.map
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { DashboardActionValidationError, HELYX_SERVICE_NAMES, } from "@helyx/sdk";
|
|
2
|
-
import { ACCOUNT_GATE_IDENTITY } from "./contracts.js";
|
|
3
|
-
import { parseAccountGateConfiguration } from "./configuration.js";
|
|
4
|
-
import { managedResourceSummary } from "./managed-resource-summary.js";
|
|
5
|
-
import { hashPasswordEntryPhrase } from "./password-entry.js";
|
|
6
|
-
const RESOURCE_ID = "shared-phrase";
|
|
7
|
-
const select = [
|
|
8
|
-
"guild_id",
|
|
9
|
-
"encoded_hash",
|
|
10
|
-
"ignore_case",
|
|
11
|
-
"trim_whitespace",
|
|
12
|
-
"revision",
|
|
13
|
-
"created_at",
|
|
14
|
-
"updated_at",
|
|
15
|
-
];
|
|
16
|
-
export const passwordEntryPhraseResource = {
|
|
17
|
-
id: "password-entry-phrase",
|
|
18
|
-
availableWhileDisabled: true,
|
|
19
|
-
async list(context) {
|
|
20
|
-
const row = await findSecret(context.services, context.guildId);
|
|
21
|
-
return { items: row ? [managedResourceSummary(safeDetail(row))] : [] };
|
|
22
|
-
},
|
|
23
|
-
async read(context, resourceId) {
|
|
24
|
-
if (resourceId !== RESOURCE_ID)
|
|
25
|
-
return null;
|
|
26
|
-
const row = await findSecret(context.services, context.guildId);
|
|
27
|
-
return row ? safeDetail(row) : null;
|
|
28
|
-
},
|
|
29
|
-
preview() {
|
|
30
|
-
return Promise.resolve({
|
|
31
|
-
ephemeral: true,
|
|
32
|
-
embed: {
|
|
33
|
-
title: "Password Entry phrase",
|
|
34
|
-
description: "The replacement phrase will be converted to a one-way hash. The phrase and hash are not shown after saving.",
|
|
35
|
-
color: 0x7c3aed,
|
|
36
|
-
},
|
|
37
|
-
});
|
|
38
|
-
},
|
|
39
|
-
async create(context, value) {
|
|
40
|
-
const records = context.services.get(HELYX_SERVICE_NAMES.records);
|
|
41
|
-
if (await findSecret(context.services, context.guildId)) {
|
|
42
|
-
throw new DashboardActionValidationError("A shared phrase is already configured. Open it and replace the phrase.");
|
|
43
|
-
}
|
|
44
|
-
const rules = await currentRules(context.services, context.guildId);
|
|
45
|
-
const encodedHash = await hashPasswordEntryPhrase(replacementPhrase(value), rules);
|
|
46
|
-
const now = new Date();
|
|
47
|
-
const result = await records.appendUnique({
|
|
48
|
-
moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
|
|
49
|
-
collection: "password_secrets",
|
|
50
|
-
uniqueBy: ["guild_id"],
|
|
51
|
-
values: {
|
|
52
|
-
guild_id: context.guildId,
|
|
53
|
-
encoded_hash: encodedHash,
|
|
54
|
-
ignore_case: rules.ignoreCase,
|
|
55
|
-
trim_whitespace: rules.trimWhitespace,
|
|
56
|
-
revision: 1,
|
|
57
|
-
created_at: now,
|
|
58
|
-
updated_at: now,
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
if (!result.created) {
|
|
62
|
-
throw new DashboardActionValidationError("The shared phrase changed in another session. Reload and try again.");
|
|
63
|
-
}
|
|
64
|
-
return safeDetail({
|
|
65
|
-
revision: 1,
|
|
66
|
-
updated_at: now,
|
|
67
|
-
});
|
|
68
|
-
},
|
|
69
|
-
async update(context, input) {
|
|
70
|
-
if (input.resourceId !== RESOURCE_ID) {
|
|
71
|
-
throw new DashboardActionValidationError("The Password Entry phrase was not found.");
|
|
72
|
-
}
|
|
73
|
-
const rules = await currentRules(context.services, context.guildId);
|
|
74
|
-
const encodedHash = await hashPasswordEntryPhrase(replacementPhrase(input.value), rules);
|
|
75
|
-
const now = new Date();
|
|
76
|
-
const result = await context.services
|
|
77
|
-
.get(HELYX_SERVICE_NAMES.records)
|
|
78
|
-
.updateOne({
|
|
79
|
-
moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
|
|
80
|
-
collection: "password_secrets",
|
|
81
|
-
where: { guild_id: context.guildId },
|
|
82
|
-
expected: { field: "revision", value: input.expectedRevision },
|
|
83
|
-
values: {
|
|
84
|
-
encoded_hash: encodedHash,
|
|
85
|
-
ignore_case: rules.ignoreCase,
|
|
86
|
-
trim_whitespace: rules.trimWhitespace,
|
|
87
|
-
revision: input.expectedRevision + 1,
|
|
88
|
-
updated_at: now,
|
|
89
|
-
},
|
|
90
|
-
audit: {
|
|
91
|
-
guildId: context.guildId,
|
|
92
|
-
actorUserId: context.actor.userId,
|
|
93
|
-
action: "account_gate.password_phrase_replaced",
|
|
94
|
-
source: "dashboard",
|
|
95
|
-
correlationId: context.correlationId,
|
|
96
|
-
idempotencyKey: context.correlationId,
|
|
97
|
-
targetType: "account_gate_password_phrase",
|
|
98
|
-
targetId: context.guildId,
|
|
99
|
-
metadata: { revision: input.expectedRevision + 1 },
|
|
100
|
-
},
|
|
101
|
-
});
|
|
102
|
-
if (!result.updated) {
|
|
103
|
-
throw new DashboardActionValidationError("The shared phrase changed in another session. Reload and try again.");
|
|
104
|
-
}
|
|
105
|
-
return safeDetail({
|
|
106
|
-
revision: input.expectedRevision + 1,
|
|
107
|
-
updated_at: now,
|
|
108
|
-
});
|
|
109
|
-
},
|
|
110
|
-
async delete(context, input) {
|
|
111
|
-
if (input.resourceId !== RESOURCE_ID)
|
|
112
|
-
return { deleted: false };
|
|
113
|
-
const current = await findSecret(context.services, context.guildId);
|
|
114
|
-
if (!current || number(current.revision) !== input.expectedRevision) {
|
|
115
|
-
throw new DashboardActionValidationError("The shared phrase changed in another session. Reload and try again.");
|
|
116
|
-
}
|
|
117
|
-
const result = await context.services
|
|
118
|
-
.get(HELYX_SERVICE_NAMES.records)
|
|
119
|
-
.deleteMany({
|
|
120
|
-
moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
|
|
121
|
-
collection: "password_secrets",
|
|
122
|
-
where: { guild_id: context.guildId },
|
|
123
|
-
limit: 1,
|
|
124
|
-
});
|
|
125
|
-
return { deleted: result.deleted === 1 };
|
|
126
|
-
},
|
|
127
|
-
executeAction() {
|
|
128
|
-
return Promise.reject(new DashboardActionValidationError("Password Entry phrase actions are not supported."));
|
|
129
|
-
},
|
|
130
|
-
};
|
|
131
|
-
export async function getPasswordSecret(records, guildId) {
|
|
132
|
-
const row = await records.findOne({
|
|
133
|
-
moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
|
|
134
|
-
collection: "password_secrets",
|
|
135
|
-
select,
|
|
136
|
-
where: { guild_id: guildId },
|
|
137
|
-
});
|
|
138
|
-
if (!row)
|
|
139
|
-
return null;
|
|
140
|
-
return {
|
|
141
|
-
encodedHash: string(row.encoded_hash),
|
|
142
|
-
ignoreCase: boolean(row.ignore_case),
|
|
143
|
-
trimWhitespace: boolean(row.trim_whitespace),
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
function safeDetail(row) {
|
|
147
|
-
const updatedAt = row.updated_at instanceof Date ? row.updated_at : new Date(0);
|
|
148
|
-
return {
|
|
149
|
-
id: RESOURCE_ID,
|
|
150
|
-
revision: number(row.revision),
|
|
151
|
-
status: "configured",
|
|
152
|
-
title: "Password Entry phrase",
|
|
153
|
-
description: "A one-way phrase hash is configured. Enter a replacement to change it.",
|
|
154
|
-
attributes: {
|
|
155
|
-
phraseConfigured: true,
|
|
156
|
-
},
|
|
157
|
-
updatedAt: updatedAt.toISOString(),
|
|
158
|
-
value: {
|
|
159
|
-
replacementPhrase: "",
|
|
160
|
-
},
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
async function findSecret(services, guildId) {
|
|
164
|
-
return services
|
|
165
|
-
.get(HELYX_SERVICE_NAMES.records)
|
|
166
|
-
.findOne({
|
|
167
|
-
moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
|
|
168
|
-
collection: "password_secrets",
|
|
169
|
-
select,
|
|
170
|
-
where: { guild_id: guildId },
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
async function currentRules(services, guildId) {
|
|
174
|
-
const record = await services
|
|
175
|
-
.get(HELYX_SERVICE_NAMES.configuration)
|
|
176
|
-
.get(guildId, ACCOUNT_GATE_IDENTITY.moduleId);
|
|
177
|
-
if (!record) {
|
|
178
|
-
throw new DashboardActionValidationError("Save the Access Control settings before configuring a shared phrase.");
|
|
179
|
-
}
|
|
180
|
-
const configuration = parseAccountGateConfiguration(record.value);
|
|
181
|
-
return {
|
|
182
|
-
ignoreCase: configuration.passwordIgnoreCase,
|
|
183
|
-
trimWhitespace: configuration.passwordTrimWhitespace,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
function replacementPhrase(value) {
|
|
187
|
-
const phrase = value.replacementPhrase;
|
|
188
|
-
if (typeof phrase !== "string") {
|
|
189
|
-
throw new DashboardActionValidationError("Enter a replacement phrase containing 4 to 200 characters.");
|
|
190
|
-
}
|
|
191
|
-
return phrase;
|
|
192
|
-
}
|
|
193
|
-
function string(value) {
|
|
194
|
-
if (typeof value !== "string")
|
|
195
|
-
throw new Error("Password secret is invalid");
|
|
196
|
-
return value;
|
|
197
|
-
}
|
|
198
|
-
function boolean(value) {
|
|
199
|
-
if (typeof value !== "boolean")
|
|
200
|
-
throw new Error("Password secret is invalid");
|
|
201
|
-
return value;
|
|
202
|
-
}
|
|
203
|
-
function number(value) {
|
|
204
|
-
if (typeof value !== "number" || !Number.isSafeInteger(value))
|
|
205
|
-
throw new Error("Password secret is invalid");
|
|
206
|
-
return value;
|
|
207
|
-
}
|
|
208
|
-
//# sourceMappingURL=password-resource.js.map
|