@farm.js/supabase 0.1.0-beta.96 → 0.1.0-beta.98
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/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +60 -4
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,14 @@ export interface SupabaseIntegrationInput {
|
|
|
35
35
|
providers?: string[];
|
|
36
36
|
defaultProvider?: string;
|
|
37
37
|
pages?: SupabaseIntegrationPages;
|
|
38
|
+
/**
|
|
39
|
+
* Additional origins allowed to submit the sign-in, sign-up, and sign-out
|
|
40
|
+
* routes, using the same pattern syntax as `serverActions.allowedOrigins`
|
|
41
|
+
* (`https://app.example.com`, `example.com`, `*.example.com`). The app's own
|
|
42
|
+
* origin is always trusted; set this only when a different trusted origin
|
|
43
|
+
* posts these forms.
|
|
44
|
+
*/
|
|
45
|
+
allowedOrigins?: string[];
|
|
38
46
|
log?: FarmIntegrationLogger;
|
|
39
47
|
}
|
|
40
48
|
interface ResolvedSupabaseEnv {
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAsB,MAAM,eAAe,CAAC;AACvE,OAAO,EAEL,KAAK,6BAA6B,EAClC,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAsB,MAAM,eAAe,CAAC;AACvE,OAAO,EAEL,KAAK,6BAA6B,EAClC,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAC;AAsCvB,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,yBAAyB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9E,MAAM,MAAM,gCAAgC,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;AAExF,MAAM,WAAW,kCAAkC;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,OAAO,kBAAkB,CAAC;IACxC,OAAO,EAAE,gCAAgC,CAAC;CAC3C;AAED;;;;;GAKG;AACH,MAAM,MAAM,2BAA2B,GAAG,CACxC,OAAO,EAAE,kCAAkC,KACxC,yBAAyB,CAAC;AAE/B,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,2BAA2B,CAAC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,wBAAwB,CAAC;IACjC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,GAAG,CAAC,EAAE,qBAAqB,CAAC;CAC7B;AAED,UAAU,mBAAmB;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,qBAAqB;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAwuBD,wBAAgB,QAAQ,CAAC,KAAK,GAAE,wBAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAuG7B,OAAO,WAAW,6BAA6B;;;;0BA2czC,OAAO,WAAW,6BAA6B;;GAiCpF"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createServerClient } from "@supabase/ssr";
|
|
2
2
|
import { defineIntegration, } from "@farm.js/core";
|
|
3
|
+
import { describeIntegrationOriginRejection, resolveIntegrationAllowedOrigins, validateIntegrationRequestOrigin, } from "@farm.js/core/integrations";
|
|
3
4
|
import { api as clientApi } from "@farm.js/core/client";
|
|
4
5
|
import { createPathInferredClientApi, createDocumentNavigationMatchers, escapeHtml, getOrigin, getReturnTo, integrationConfig, normalizeMatchers, parseCookieHeaderList, resolveAppPath, resolveCallbackSettings, toAbsoluteUrl, withSearchParams, } from "@farm.js/integration-utils";
|
|
5
6
|
import { supabaseAuthFormFields, } from "./client.js";
|
|
@@ -657,12 +658,33 @@ export function supabase(input = {}) {
|
|
|
657
658
|
label: "Supabase integration",
|
|
658
659
|
}, env.appBaseUrl);
|
|
659
660
|
const callbackPath = callbackSettings.callbackPath;
|
|
661
|
+
const allowedOrigins = resolveIntegrationAllowedOrigins(input.allowedOrigins, "supabase.allowedOrigins");
|
|
660
662
|
const api = createSupabaseApi({
|
|
661
663
|
loginPath,
|
|
662
664
|
signupPath,
|
|
663
665
|
logoutPath,
|
|
664
666
|
sessionPath,
|
|
665
667
|
});
|
|
668
|
+
/**
|
|
669
|
+
* Reject a credential or sign-out request that did not come from this app.
|
|
670
|
+
* Returns the response to send, or null when the request may proceed.
|
|
671
|
+
*/
|
|
672
|
+
function rejectForeignOrigin(request, clientRequest, { requireOriginMetadata }) {
|
|
673
|
+
const result = validateIntegrationRequestOrigin(request, {
|
|
674
|
+
allowedOrigins,
|
|
675
|
+
requireOriginMetadata,
|
|
676
|
+
});
|
|
677
|
+
if (result.ok) {
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
const message = describeIntegrationOriginRejection(result.reason);
|
|
681
|
+
return clientRequest
|
|
682
|
+
? jsonError(message, 403)
|
|
683
|
+
: new Response(message, {
|
|
684
|
+
status: 403,
|
|
685
|
+
headers: { "content-type": "text/plain; charset=utf-8" },
|
|
686
|
+
});
|
|
687
|
+
}
|
|
666
688
|
return defineIntegration({
|
|
667
689
|
category: "auth",
|
|
668
690
|
type: "supabase",
|
|
@@ -706,6 +728,12 @@ export function supabase(input = {}) {
|
|
|
706
728
|
const provider = requestUrl.searchParams.get("provider") || input.defaultProvider;
|
|
707
729
|
const returnTo = getReturnTo(requestUrl.searchParams.get("returnTo"), "/dashboard");
|
|
708
730
|
if (request.method === "POST") {
|
|
731
|
+
const rejected = rejectForeignOrigin(request, clientRequest, {
|
|
732
|
+
requireOriginMetadata: true,
|
|
733
|
+
});
|
|
734
|
+
if (rejected) {
|
|
735
|
+
return rejected;
|
|
736
|
+
}
|
|
709
737
|
const parsedRequest = await parseEmailPasswordRequest(request);
|
|
710
738
|
if (!parsedRequest.ok) {
|
|
711
739
|
if (clientRequest) {
|
|
@@ -856,6 +884,12 @@ export function supabase(input = {}) {
|
|
|
856
884
|
feedback: readPageFeedback(context),
|
|
857
885
|
});
|
|
858
886
|
}
|
|
887
|
+
const rejected = rejectForeignOrigin(request, clientRequest, {
|
|
888
|
+
requireOriginMetadata: true,
|
|
889
|
+
});
|
|
890
|
+
if (rejected) {
|
|
891
|
+
return rejected;
|
|
892
|
+
}
|
|
859
893
|
const parsedRequest = await parseEmailPasswordRequest(context.request);
|
|
860
894
|
if (!parsedRequest.ok) {
|
|
861
895
|
if (clientRequest) {
|
|
@@ -985,6 +1019,16 @@ export function supabase(input = {}) {
|
|
|
985
1019
|
const requestUrl = context.url;
|
|
986
1020
|
let returnTo = getReturnTo(requestUrl.searchParams.get("returnTo"), "/");
|
|
987
1021
|
const clientRequest = isIntegrationClientRequest(request);
|
|
1022
|
+
// A POST carries an Origin in every supported browser, so it is held
|
|
1023
|
+
// to the strict check. A GET sign-out is also reachable as a plain
|
|
1024
|
+
// link or bookmark, where no origin metadata exists at all; those
|
|
1025
|
+
// stay allowed and only an explicitly cross-site GET is rejected.
|
|
1026
|
+
const rejected = rejectForeignOrigin(request, clientRequest, {
|
|
1027
|
+
requireOriginMetadata: request.method === "POST",
|
|
1028
|
+
});
|
|
1029
|
+
if (rejected) {
|
|
1030
|
+
return rejected;
|
|
1031
|
+
}
|
|
988
1032
|
if (request.method === "POST") {
|
|
989
1033
|
const contentType = context.request.headers.get("content-type") || "";
|
|
990
1034
|
if (contentType.includes("application/json")) {
|
|
@@ -1046,14 +1090,26 @@ export function supabase(input = {}) {
|
|
|
1046
1090
|
{
|
|
1047
1091
|
matcher: protectedMatchers,
|
|
1048
1092
|
async handler(_request, context) {
|
|
1049
|
-
const { supabase } = createSupabaseHandler(context, env, input.instance);
|
|
1050
|
-
|
|
1051
|
-
|
|
1093
|
+
const { supabase, setCookies } = createSupabaseHandler(context, env, input.instance);
|
|
1094
|
+
// getSession() reads the cookie without verifying the token,
|
|
1095
|
+
// so a forged cookie would pass this gate. getUser() checks
|
|
1096
|
+
// the token against Supabase Auth before the route is served.
|
|
1097
|
+
const { data, error } = await supabase.auth.getUser();
|
|
1098
|
+
if (!error && data?.user) {
|
|
1052
1099
|
return;
|
|
1053
1100
|
}
|
|
1054
|
-
|
|
1101
|
+
const redirect = redirectToPage(signInViewPath, context, env.appBaseUrl, {
|
|
1055
1102
|
returnTo: `${context.url.pathname}${context.url.search}`,
|
|
1056
1103
|
});
|
|
1104
|
+
if (setCookies.length === 0) {
|
|
1105
|
+
return redirect;
|
|
1106
|
+
}
|
|
1107
|
+
// A failed validation can clear or rotate auth cookies; keep
|
|
1108
|
+
// those directives on the redirect so the browser drops the
|
|
1109
|
+
// stale session instead of replaying it on the next request.
|
|
1110
|
+
const headers = new Headers(redirect.headers);
|
|
1111
|
+
appendSetCookies(headers, setCookies);
|
|
1112
|
+
return new Response(null, { status: redirect.status, headers });
|
|
1057
1113
|
},
|
|
1058
1114
|
},
|
|
1059
1115
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farm.js/supabase",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.98",
|
|
4
4
|
"description": "Supabase integration for Farm.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@supabase/ssr": "^0.9.0",
|
|
33
33
|
"@supabase/supabase-js": "^2.99.2",
|
|
34
|
-
"@farm.js/core": "0.1.0-beta.
|
|
35
|
-
"@farm.js/integration-utils": "0.1.0-beta.
|
|
34
|
+
"@farm.js/core": "0.1.0-beta.98",
|
|
35
|
+
"@farm.js/integration-utils": "0.1.0-beta.98"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc",
|