@lobb-js/lobb-ext-auth 0.15.0 → 0.16.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/dist/lib/components/pages/loginPage/index.svelte +15 -24
- package/dist/lib/components/pages/settings/index.svelte +17 -21
- package/dist/lib/components/pages/settings/pages/activityFeed.svelte +3 -5
- package/dist/lib/components/pages/settings/pages/rolesAndPermissions.svelte +3 -5
- package/dist/lib/components/pages/settings/pages/users.svelte +3 -5
- package/dist/lib/components/pages/userSettings/index.svelte +21 -27
- package/extensions/auth/collections/activityFeed.ts +3 -4
- package/extensions/auth/collections/sessions.ts +2 -2
- package/extensions/auth/collections/shares.ts +2 -2
- package/extensions/auth/collections/users.ts +2 -2
- package/extensions/auth/config/extensionConfigSchema.d.ts +2 -2
- package/extensions/auth/config/extensionConfigSchema.ts +2 -2
- package/extensions/auth/workflows/baseWorkflow.ts +19 -3
- package/package.json +4 -3
|
@@ -1,27 +1,18 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
e.preventDefault();
|
|
17
|
-
if (!formData.email && !formData.password) {
|
|
18
|
-
utils.toast.error("Please complete all fields");
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const auth = new Auth(utils);
|
|
23
|
-
await auth.login(formData);
|
|
24
|
-
}
|
|
1
|
+
<script lang="ts">import { Auth } from "../../../../auth";
|
|
2
|
+
const { utils } = $props();
|
|
3
|
+
let formData = {
|
|
4
|
+
email: window.location.hostname === "demo.lobb.app" ? "admin@example.com" : "",
|
|
5
|
+
password: window.location.hostname === "demo.lobb.app" ? "admin" : ""
|
|
6
|
+
};
|
|
7
|
+
async function handleOnSubmit(e) {
|
|
8
|
+
e.preventDefault();
|
|
9
|
+
if (!formData.email && !formData.password) {
|
|
10
|
+
utils.toast.error("Please complete all fields");
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const auth = new Auth(utils);
|
|
14
|
+
await auth.login(formData);
|
|
15
|
+
}
|
|
25
16
|
</script>
|
|
26
17
|
|
|
27
18
|
<div
|
|
@@ -1,24 +1,20 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (!auth_settings_page) {
|
|
19
|
-
props.utils.goto("/studio/extensions/auth/settings/users");
|
|
20
|
-
}
|
|
21
|
-
});
|
|
1
|
+
<script lang="ts">import Users from "./pages/users.svelte";
|
|
2
|
+
import RolesAndPermissions from "./pages/rolesAndPermissions.svelte";
|
|
3
|
+
import ActivityFeed from "./pages/activityFeed.svelte";
|
|
4
|
+
const props = $props();
|
|
5
|
+
const components = props.utils.components;
|
|
6
|
+
const { Sidebar } = components;
|
|
7
|
+
const { Icons } = components;
|
|
8
|
+
const auth_settings_page = $derived(props.utils.page.url.pathname.split("/")[5]);
|
|
9
|
+
const isSmall = $derived(!props.utils.mediaQueries.sm.current);
|
|
10
|
+
// Bare /studio/extensions/auth/settings has no sub-page to render, which
|
|
11
|
+
// would leave the page blank. Redirect to the first sub-page (Users) so
|
|
12
|
+
// landing on the settings root always shows something useful.
|
|
13
|
+
$effect(() => {
|
|
14
|
+
if (!auth_settings_page) {
|
|
15
|
+
props.utils.goto("/studio/extensions/auth/settings/users");
|
|
16
|
+
}
|
|
17
|
+
});
|
|
22
18
|
</script>
|
|
23
19
|
|
|
24
20
|
<!-- TODO: add the sidebar in here to add these pages
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const { utils }: ExtensionProps = $props();
|
|
5
|
-
const components = utils.components;
|
|
1
|
+
<script lang="ts">const { utils } = $props();
|
|
2
|
+
const components = utils.components;
|
|
3
|
+
export {};
|
|
6
4
|
</script>
|
|
7
5
|
|
|
8
6
|
<div class="flex flex-col gap-4 p-4 h-full">
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const { utils }: ExtensionProps = $props();
|
|
5
|
-
const components = utils.components;
|
|
1
|
+
<script lang="ts">const { utils } = $props();
|
|
2
|
+
const components = utils.components;
|
|
3
|
+
export {};
|
|
6
4
|
</script>
|
|
7
5
|
|
|
8
6
|
<div class="flex flex-col gap-4 p-4 h-full">
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const { utils }: ExtensionProps = $props();
|
|
5
|
-
const components = utils.components;
|
|
1
|
+
<script lang="ts">const { utils } = $props();
|
|
2
|
+
const components = utils.components;
|
|
3
|
+
export {};
|
|
6
4
|
</script>
|
|
7
5
|
|
|
8
6
|
<div class="flex flex-col gap-4 p-4 h-full">
|
|
@@ -1,32 +1,26 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
<script lang="ts">import { DetailView } from "@lobb-js/studio";
|
|
2
|
+
import { onMount } from "svelte";
|
|
3
|
+
const { utils } = $props();
|
|
4
|
+
const { Button, Separator, Skeleton, Icons } = utils.components;
|
|
5
|
+
let entry = $state({});
|
|
6
|
+
let loading = $state(true);
|
|
7
|
+
onMount(async () => {
|
|
8
|
+
// /me is the only auth_users path a role without explicit auth_users
|
|
9
|
+
// read perms can reach (self-bypass at the policy layer).
|
|
10
|
+
const response = await utils.lobb.findOne("auth_users", "me");
|
|
11
|
+
const result = await response.json();
|
|
12
|
+
entry = result.data;
|
|
13
|
+
loading = false;
|
|
14
|
+
});
|
|
15
|
+
async function handleSave() {
|
|
16
|
+
const response = await utils.lobb.updateOne("auth_users", "me", { data: entry });
|
|
17
|
+
if (response.status >= 400) {
|
|
16
18
|
const result = await response.json();
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
async function handleSave() {
|
|
22
|
-
const response = await utils.lobb.updateOne("auth_users", "me", { data: entry });
|
|
23
|
-
if (response.status >= 400) {
|
|
24
|
-
const result = await response.json();
|
|
25
|
-
utils.toast.error(result.message);
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
utils.toast.success("Profile updated successfully.");
|
|
19
|
+
utils.toast.error(result.message);
|
|
20
|
+
return;
|
|
29
21
|
}
|
|
22
|
+
utils.toast.success("Profile updated successfully.");
|
|
23
|
+
}
|
|
30
24
|
</script>
|
|
31
25
|
|
|
32
26
|
<div class="flex flex-col gap-4 p-4">
|
|
@@ -4,10 +4,10 @@ export const activityFeedCollection: CollectionConfig = {
|
|
|
4
4
|
indexes: {},
|
|
5
5
|
fields: {
|
|
6
6
|
id: {
|
|
7
|
-
type: "
|
|
7
|
+
type: "id",
|
|
8
8
|
},
|
|
9
9
|
user_id: {
|
|
10
|
-
type: "
|
|
10
|
+
type: "id",
|
|
11
11
|
references: {
|
|
12
12
|
collection: "auth_users",
|
|
13
13
|
field: "id",
|
|
@@ -31,8 +31,7 @@ export const activityFeedCollection: CollectionConfig = {
|
|
|
31
31
|
required: true,
|
|
32
32
|
},
|
|
33
33
|
item_id: {
|
|
34
|
-
type: "
|
|
35
|
-
length: 255,
|
|
34
|
+
type: "id",
|
|
36
35
|
required: true,
|
|
37
36
|
},
|
|
38
37
|
created_at: {
|
|
@@ -10,7 +10,7 @@ export const sharesCollection: CollectionConfig = {
|
|
|
10
10
|
indexes: {},
|
|
11
11
|
fields: {
|
|
12
12
|
id: {
|
|
13
|
-
type: "
|
|
13
|
+
type: "id",
|
|
14
14
|
},
|
|
15
15
|
// Auto-generated server-side by the auth_generateShareToken workflow on
|
|
16
16
|
// create — clients should not supply this; the generated token comes
|
|
@@ -49,7 +49,7 @@ export const sharesCollection: CollectionConfig = {
|
|
|
49
49
|
ui: { hidden: true },
|
|
50
50
|
},
|
|
51
51
|
created_by: {
|
|
52
|
-
type: "
|
|
52
|
+
type: "id",
|
|
53
53
|
references: {
|
|
54
54
|
collection: "auth_users",
|
|
55
55
|
field: "id",
|
|
@@ -14,7 +14,7 @@ export const usersCollection: NormalCollectionConfig = {
|
|
|
14
14
|
},
|
|
15
15
|
fields: {
|
|
16
16
|
id: {
|
|
17
|
-
type: "
|
|
17
|
+
type: "id",
|
|
18
18
|
},
|
|
19
19
|
email: {
|
|
20
20
|
type: "string",
|
|
@@ -37,7 +37,7 @@ export const usersCollection: NormalCollectionConfig = {
|
|
|
37
37
|
},
|
|
38
38
|
role: {
|
|
39
39
|
type: "string",
|
|
40
|
-
length:
|
|
40
|
+
length: 100,
|
|
41
41
|
required: true,
|
|
42
42
|
},
|
|
43
43
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CollectionConfig } from "@lobb-js/core";
|
|
1
|
+
import type { CollectionConfig, CollectionField } from "@lobb-js/core";
|
|
2
2
|
import type { CreatePermissionAction } from "./permissionsAction/create.ts";
|
|
3
3
|
import type { ReadPermissionAction } from "./permissionsAction/read.ts";
|
|
4
4
|
import type { UpdatePermissionAction } from "./permissionsAction/update.ts";
|
|
@@ -33,7 +33,7 @@ export type ExtensionConfig = {
|
|
|
33
33
|
roles?: Record<string, RolesConfig | undefined>;
|
|
34
34
|
extend_users?: {
|
|
35
35
|
indexes?: CollectionConfig["indexes"];
|
|
36
|
-
fields?:
|
|
36
|
+
fields?: Record<string, CollectionField>;
|
|
37
37
|
};
|
|
38
38
|
studio?: {
|
|
39
39
|
publicPaths?: string[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CollectionConfig } from "@lobb-js/core";
|
|
1
|
+
import type { CollectionConfig, CollectionField } from "@lobb-js/core";
|
|
2
2
|
import type { CreatePermissionAction } from "./permissionsAction/create.ts";
|
|
3
3
|
import type { ReadPermissionAction } from "./permissionsAction/read.ts";
|
|
4
4
|
import type { UpdatePermissionAction } from "./permissionsAction/update.ts";
|
|
@@ -43,7 +43,7 @@ export type ExtensionConfig = {
|
|
|
43
43
|
roles?: Record<string, RolesConfig | undefined>;
|
|
44
44
|
extend_users?: {
|
|
45
45
|
indexes?: CollectionConfig["indexes"];
|
|
46
|
-
fields?:
|
|
46
|
+
fields?: Record<string, CollectionField>;
|
|
47
47
|
};
|
|
48
48
|
studio?: {
|
|
49
49
|
publicPaths?: string[];
|
|
@@ -3,7 +3,23 @@ import type { Context } from "hono";
|
|
|
3
3
|
import type { ExtensionConfig } from "../config/extensionConfigSchema.ts";
|
|
4
4
|
import { getBearerToken } from "../utils.ts";
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
// The admin user is identified by the configured admin email — its id is a uuid
|
|
7
|
+
// now, no longer a predictable "1". Looks the target user up and compares.
|
|
8
|
+
async function isAdminUser(id: any, ctx: any, adminEmail?: string): Promise<boolean> {
|
|
9
|
+
if (!adminEmail || id == null) return false;
|
|
10
|
+
try {
|
|
11
|
+
const user = (await ctx.lobb.collectionStore.findOne({
|
|
12
|
+
collectionName: "auth_users",
|
|
13
|
+
id: String(id),
|
|
14
|
+
params: { fields: "id,email" },
|
|
15
|
+
})).data;
|
|
16
|
+
return user?.email === adminEmail;
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function getBaseWorkflows(extensionConfig: ExtensionConfig): Workflow[] {
|
|
7
23
|
return [
|
|
8
24
|
{
|
|
9
25
|
name: "auth_preventAdminUserDeletion",
|
|
@@ -12,7 +28,7 @@ export function getBaseWorkflows(_extensionConfig: ExtensionConfig): Workflow[]
|
|
|
12
28
|
if (
|
|
13
29
|
input.collectionName === "auth_users" &&
|
|
14
30
|
input.triggeredBy === "API" &&
|
|
15
|
-
|
|
31
|
+
await isAdminUser(input.id, ctx, extensionConfig.admin?.email)
|
|
16
32
|
) {
|
|
17
33
|
throw new ctx.LobbError({
|
|
18
34
|
code: "FORBIDDEN",
|
|
@@ -28,7 +44,7 @@ export function getBaseWorkflows(_extensionConfig: ExtensionConfig): Workflow[]
|
|
|
28
44
|
if (
|
|
29
45
|
input.collectionName === "auth_users" &&
|
|
30
46
|
input.triggeredBy === "API" &&
|
|
31
|
-
|
|
47
|
+
await isAdminUser(input.id, ctx, extensionConfig.admin?.email)
|
|
32
48
|
) {
|
|
33
49
|
// Only the security-sensitive core fields are locked on the admin —
|
|
34
50
|
// changing them could lock out or hijack the account. Other fields
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobb-js/lobb-ext-auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -32,12 +32,13 @@
|
|
|
32
32
|
"package": "svelte-package --input extensions/auth/studio"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@lobb-js/core": "^0.
|
|
35
|
+
"@lobb-js/core": "^0.50.0",
|
|
36
36
|
"argon2": "^0.40.3",
|
|
37
37
|
"hono": "^4.7.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@
|
|
40
|
+
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
|
41
|
+
"@lobb-js/studio": "^0.60.0",
|
|
41
42
|
"@lucide/svelte": "^0.563.1",
|
|
42
43
|
"@sveltejs/adapter-node": "^5.5.4",
|
|
43
44
|
"@sveltejs/kit": "^2.60.1",
|