@autumnsgrove/groveengine 0.4.1 → 0.4.3
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/auth/session.d.ts +18 -0
- package/dist/auth/session.js +64 -2
- package/dist/ui/components/ui/Toast.svelte +1 -1
- package/package.json +22 -21
package/dist/auth/session.d.ts
CHANGED
|
@@ -40,3 +40,21 @@ export function parseSessionCookie(cookieHeader: string): string | null;
|
|
|
40
40
|
* @returns {boolean} - Whether the user is allowed
|
|
41
41
|
*/
|
|
42
42
|
export function isAllowedAdmin(email: string, allowedList: string): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Verify that a user owns/has access to a tenant
|
|
45
|
+
* @param {Object} db - D1 database instance
|
|
46
|
+
* @param {string} tenantId - Tenant ID to check
|
|
47
|
+
* @param {string} userEmail - User's email address
|
|
48
|
+
* @returns {Promise<boolean>} - Whether the user owns the tenant
|
|
49
|
+
*/
|
|
50
|
+
export function verifyTenantOwnership(db: Object, tenantId: string, userEmail: string): Promise<boolean>;
|
|
51
|
+
/**
|
|
52
|
+
* Get tenant ID with ownership verification
|
|
53
|
+
* Throws 403 if user doesn't own the tenant
|
|
54
|
+
* @param {Object} db - D1 database instance
|
|
55
|
+
* @param {string} tenantId - Tenant ID from request
|
|
56
|
+
* @param {Object} user - User object with email
|
|
57
|
+
* @returns {Promise<string>} - Verified tenant ID
|
|
58
|
+
* @throws {Error} - If unauthorized
|
|
59
|
+
*/
|
|
60
|
+
export function getVerifiedTenantId(db: Object, tenantId: string, user: Object): Promise<string>;
|
package/dist/auth/session.js
CHANGED
|
@@ -54,7 +54,7 @@ export function createSessionCookie(token, isProduction = true) {
|
|
|
54
54
|
"Path=/",
|
|
55
55
|
`Max-Age=${SESSION_DURATION_SECONDS}`,
|
|
56
56
|
"HttpOnly",
|
|
57
|
-
"SameSite=
|
|
57
|
+
"SameSite=Strict",
|
|
58
58
|
];
|
|
59
59
|
|
|
60
60
|
if (isProduction) {
|
|
@@ -69,7 +69,7 @@ export function createSessionCookie(token, isProduction = true) {
|
|
|
69
69
|
* @returns {string} - Cookie header value
|
|
70
70
|
*/
|
|
71
71
|
export function clearSessionCookie() {
|
|
72
|
-
return `${SESSION_COOKIE_NAME}=; Path=/; Max-Age=0; HttpOnly; SameSite=
|
|
72
|
+
return `${SESSION_COOKIE_NAME}=; Path=/; Max-Age=0; HttpOnly; SameSite=Strict`;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/**
|
|
@@ -103,3 +103,65 @@ export function isAllowedAdmin(email, allowedList) {
|
|
|
103
103
|
const allowed = allowedList.split(",").map((e) => e.trim().toLowerCase());
|
|
104
104
|
return allowed.includes(email.toLowerCase());
|
|
105
105
|
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Verify that a user owns/has access to a tenant
|
|
109
|
+
* @param {Object} db - D1 database instance
|
|
110
|
+
* @param {string} tenantId - Tenant ID to check
|
|
111
|
+
* @param {string} userEmail - User's email address
|
|
112
|
+
* @returns {Promise<boolean>} - Whether the user owns the tenant
|
|
113
|
+
*/
|
|
114
|
+
export async function verifyTenantOwnership(db, tenantId, userEmail) {
|
|
115
|
+
if (!tenantId || !userEmail) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const tenant = await db
|
|
121
|
+
.prepare("SELECT email FROM tenants WHERE id = ?")
|
|
122
|
+
.bind(tenantId)
|
|
123
|
+
.first();
|
|
124
|
+
|
|
125
|
+
if (!tenant) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Check if user email matches tenant owner email
|
|
130
|
+
return tenant.email.toLowerCase() === userEmail.toLowerCase();
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error("Error verifying tenant ownership:", error);
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get tenant ID with ownership verification
|
|
139
|
+
* Throws 403 if user doesn't own the tenant
|
|
140
|
+
* @param {Object} db - D1 database instance
|
|
141
|
+
* @param {string} tenantId - Tenant ID from request
|
|
142
|
+
* @param {Object} user - User object with email
|
|
143
|
+
* @returns {Promise<string>} - Verified tenant ID
|
|
144
|
+
* @throws {Error} - If unauthorized
|
|
145
|
+
*/
|
|
146
|
+
export async function getVerifiedTenantId(db, tenantId, user) {
|
|
147
|
+
if (!tenantId) {
|
|
148
|
+
const err = new Error("Tenant ID required");
|
|
149
|
+
err.status = 400;
|
|
150
|
+
throw err;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!user?.email) {
|
|
154
|
+
const err = new Error("Unauthorized");
|
|
155
|
+
err.status = 401;
|
|
156
|
+
throw err;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const isOwner = await verifyTenantOwnership(db, tenantId, user.email);
|
|
160
|
+
if (!isOwner) {
|
|
161
|
+
const err = new Error("Access denied - you do not own this tenant");
|
|
162
|
+
err.status = 403;
|
|
163
|
+
throw err;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return tenantId;
|
|
167
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autumnsgrove/groveengine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Multi-tenant blog engine for Grove Platform. Features gutter annotations, markdown editing, magic code auth, and Cloudflare Workers deployment.",
|
|
5
5
|
"author": "AutumnsGrove",
|
|
6
6
|
"license": "MIT",
|
|
@@ -129,10 +129,28 @@
|
|
|
129
129
|
"dist",
|
|
130
130
|
"!dist/**/*.test.*"
|
|
131
131
|
],
|
|
132
|
+
"scripts": {
|
|
133
|
+
"dev": "vite dev",
|
|
134
|
+
"dev:wrangler": "wrangler pages dev -- vite dev",
|
|
135
|
+
"build": "vite build",
|
|
136
|
+
"build:package": "svelte-kit sync && svelte-package -o dist",
|
|
137
|
+
"package": "svelte-kit sync && svelte-package -o dist",
|
|
138
|
+
"prepublishOnly": "pnpm run package",
|
|
139
|
+
"preview": "vite preview",
|
|
140
|
+
"audit": "pnpm audit --audit-level=moderate",
|
|
141
|
+
"audit:fix": "pnpm audit --fix",
|
|
142
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
143
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
144
|
+
"test": "vitest",
|
|
145
|
+
"test:ui": "vitest --ui",
|
|
146
|
+
"test:run": "vitest run",
|
|
147
|
+
"test:security": "vitest run tests/security",
|
|
148
|
+
"test:coverage": "vitest run --coverage",
|
|
149
|
+
"test:watch": "vitest watch"
|
|
150
|
+
},
|
|
132
151
|
"peerDependencies": {
|
|
133
152
|
"@sveltejs/kit": "^2.0.0",
|
|
134
153
|
"svelte": "^5.0.0",
|
|
135
|
-
"svelte-sonner": "^1.0.0",
|
|
136
154
|
"tailwindcss": "^3.4.0"
|
|
137
155
|
},
|
|
138
156
|
"devDependencies": {
|
|
@@ -166,24 +184,7 @@
|
|
|
166
184
|
"gray-matter": "^4.0.3",
|
|
167
185
|
"lucide-svelte": "^0.554.0",
|
|
168
186
|
"marked": "^17.0.1",
|
|
187
|
+
"svelte-sonner": "^1.0.7",
|
|
169
188
|
"tailwind-merge": "^3.4.0"
|
|
170
|
-
},
|
|
171
|
-
"scripts": {
|
|
172
|
-
"dev": "vite dev",
|
|
173
|
-
"dev:wrangler": "wrangler pages dev -- vite dev",
|
|
174
|
-
"build": "vite build",
|
|
175
|
-
"build:package": "svelte-kit sync && svelte-package -o dist",
|
|
176
|
-
"package": "svelte-kit sync && svelte-package -o dist",
|
|
177
|
-
"preview": "vite preview",
|
|
178
|
-
"audit": "npm audit --audit-level=moderate",
|
|
179
|
-
"audit:fix": "npm audit fix",
|
|
180
|
-
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
181
|
-
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
182
|
-
"test": "vitest",
|
|
183
|
-
"test:ui": "vitest --ui",
|
|
184
|
-
"test:run": "vitest run",
|
|
185
|
-
"test:security": "vitest run tests/security",
|
|
186
|
-
"test:coverage": "vitest run --coverage",
|
|
187
|
-
"test:watch": "vitest watch"
|
|
188
189
|
}
|
|
189
|
-
}
|
|
190
|
+
}
|