-
-
Notifications
You must be signed in to change notification settings - Fork 220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Modify components to support ionic fork #192
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ node_modules | |
/data/schema.sql | ||
/@app/graphql/index.* | ||
/@app/client/.next | ||
**/build | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,23 @@ | ||
import { getDataFromTree } from "@apollo/react-ssr"; | ||
import { InMemoryCache } from "apollo-cache-inmemory"; | ||
import { InMemoryCache, NormalizedCacheObject } from "apollo-cache-inmemory"; | ||
import { ApolloClient } from "apollo-client"; | ||
import { ApolloLink, split } from "apollo-link"; | ||
import { onError } from "apollo-link-error"; | ||
import { HttpLink } from "apollo-link-http"; | ||
import { WebSocketLink } from "apollo-link-ws"; | ||
import { getOperationAST } from "graphql"; | ||
import withApolloBase from "next-with-apollo"; | ||
import withApolloBase, { InitApolloOptions } from "next-with-apollo"; | ||
import React from "react"; | ||
import { SubscriptionClient } from "subscriptions-transport-ws"; | ||
import ws from "ws"; | ||
|
||
import { GraphileApolloLink } from "./GraphileApolloLink"; | ||
|
||
interface WithApolloOptions { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
useNext?: boolean; | ||
rootUrl?: string; | ||
} | ||
|
||
let wsClient: SubscriptionClient | null = null; | ||
|
||
export function resetWebsocketConnection(): void { | ||
|
@@ -29,18 +35,18 @@ function makeServerSideLink(req: any, res: any) { | |
} | ||
|
||
function makeClientSideLink(ROOT_URL: string) { | ||
const nextDataEl = document.getElementById("__NEXT_DATA__"); | ||
if (!nextDataEl || !nextDataEl.textContent) { | ||
throw new Error("Cannot read from __NEXT_DATA__ element"); | ||
const nextDataEl = | ||
typeof document !== "undefined" && document.getElementById("__NEXT_DATA__"); | ||
const headers = {}; | ||
if (nextDataEl && nextDataEl.textContent) { | ||
const data = JSON.parse(nextDataEl.textContent); | ||
headers["CSRF-Token"] = data.query.CSRF_TOKEN; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No longer require a CSRF token |
||
} | ||
const data = JSON.parse(nextDataEl.textContent); | ||
const CSRF_TOKEN = data.query.CSRF_TOKEN; | ||
const httpLink = new HttpLink({ | ||
uri: `${ROOT_URL}/graphql`, | ||
credentials: "same-origin", | ||
headers: { | ||
"CSRF-Token": CSRF_TOKEN, | ||
}, | ||
credentials: | ||
process.env.NODE_ENV === "development" ? "include" : "same-origin", | ||
headers, | ||
}); | ||
wsClient = new SubscriptionClient( | ||
`${ROOT_URL.replace(/^http/, "ws")}/graphql`, | ||
|
@@ -65,47 +71,61 @@ function makeClientSideLink(ROOT_URL: string) { | |
return mainLink; | ||
} | ||
|
||
export const withApollo = withApolloBase( | ||
({ initialState, ctx }) => { | ||
const ROOT_URL = process.env.ROOT_URL; | ||
if (!ROOT_URL) { | ||
throw new Error("ROOT_URL envvar is not set"); | ||
} | ||
const getApolloClient = ( | ||
{ initialState, ctx }: InitApolloOptions<NormalizedCacheObject>, | ||
withApolloOptions?: WithApolloOptions | ||
): ApolloClient<NormalizedCacheObject> => { | ||
const ROOT_URL = process.env.ROOT_URL || withApolloOptions?.rootUrl; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Allow us to pass in a different rootUrl in the options to |
||
if (!ROOT_URL) { | ||
throw new Error("ROOT_URL envvar is not set"); | ||
} | ||
|
||
const onErrorLink = onError(({ graphQLErrors, networkError }) => { | ||
if (graphQLErrors) | ||
graphQLErrors.map(({ message, locations, path }) => | ||
console.error( | ||
`[GraphQL error]: message: ${message}, location: ${JSON.stringify( | ||
locations | ||
)}, path: ${JSON.stringify(path)}` | ||
) | ||
); | ||
if (networkError) console.error(`[Network error]: ${networkError}`); | ||
}); | ||
|
||
const onErrorLink = onError(({ graphQLErrors, networkError }) => { | ||
if (graphQLErrors) | ||
graphQLErrors.map(({ message, locations, path }) => | ||
console.error( | ||
`[GraphQL error]: message: ${message}, location: ${JSON.stringify( | ||
locations | ||
)}, path: ${JSON.stringify(path)}` | ||
) | ||
); | ||
if (networkError) console.error(`[Network error]: ${networkError}`); | ||
}); | ||
const { req, res }: any = ctx || {}; | ||
const isServer = typeof window === "undefined"; | ||
const mainLink = | ||
isServer && req && res | ||
? makeServerSideLink(req, res) | ||
: makeClientSideLink(ROOT_URL); | ||
|
||
const { req, res }: any = ctx || {}; | ||
const isServer = typeof window === "undefined"; | ||
const mainLink = | ||
isServer && req && res | ||
? makeServerSideLink(req, res) | ||
: makeClientSideLink(ROOT_URL); | ||
const client = new ApolloClient({ | ||
link: ApolloLink.from([onErrorLink, mainLink]), | ||
cache: new InMemoryCache({ | ||
dataIdFromObject: (o) => | ||
o.__typename === "Query" | ||
? "ROOT_QUERY" | ||
: o.id | ||
? `${o.__typename}:${o.id}` | ||
: null, | ||
}).restore(initialState || {}), | ||
}); | ||
|
||
const client = new ApolloClient({ | ||
link: ApolloLink.from([onErrorLink, mainLink]), | ||
cache: new InMemoryCache({ | ||
dataIdFromObject: (o) => | ||
o.__typename === "Query" | ||
? "ROOT_QUERY" | ||
: o.id | ||
? `${o.__typename}:${o.id}` | ||
: null, | ||
}).restore(initialState || {}), | ||
}); | ||
return client; | ||
}; | ||
|
||
return client; | ||
}, | ||
{ | ||
getDataFromTree, | ||
} | ||
); | ||
const withApolloWithNext = withApolloBase(getApolloClient, { | ||
getDataFromTree, | ||
}); | ||
|
||
const withApolloWithoutNext = (Component: any, options?: WithApolloOptions) => ( | ||
props: any | ||
) => { | ||
const apollo = getApolloClient({}, options); | ||
return <Component {...props} apollo={apollo} />; | ||
}; | ||
|
||
export const withApollo = (Component: any, options?: WithApolloOptions) => | ||
options?.useNext === false | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Optionally disable nextjs processing for apollo, but enable it by default |
||
? withApolloWithoutNext(Component, options) | ||
: withApolloWithNext(Component); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,20 @@ | ||
import csrf from "csurf"; | ||
import { Express } from "express"; | ||
import url from "url"; | ||
|
||
const skipList = process.env.CSRF_SKIP_REFERERS | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Allow us to pass a list of referrers like:
|
||
? process.env.CSRF_SKIP_REFERERS?.replace(/s\s/g, "") | ||
.split(",") | ||
.map((s) => { | ||
// It is prefixed with a protocol | ||
if (s.indexOf("//") !== -1) { | ||
const { host: skipHost } = url.parse(s); | ||
return skipHost; | ||
} | ||
|
||
return s; | ||
}) | ||
: []; | ||
|
||
export default (app: Express) => { | ||
const csrfProtection = csrf({ | ||
|
@@ -21,6 +36,12 @@ export default (app: Express) => { | |
) { | ||
// Bypass CSRF for GraphiQL | ||
next(); | ||
} else if ( | ||
skipList && | ||
skipList.includes(url.parse(req.headers.referer || "").host) | ||
) { | ||
// Bypass CSRF for named referers | ||
next(); | ||
} else { | ||
csrfProtection(req, res, next); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignore any build folders, such as the one ionic generates