Skip to content
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

Farcaster login #563

Merged
merged 1 commit into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions apps/backend/src/services/auth/providers/farcaster.provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { ProvidersInterface } from '@gitroom/backend/services/auth/providers.interface';
import { NeynarAPIClient } from '@neynar/nodejs-sdk';

const client = new NeynarAPIClient({
apiKey: process.env.NEYNAR_SECRET_KEY || '00000000-000-0000-000-000000000000',
});

export class FarcasterProvider implements ProvidersInterface {
generateLink() {
return '';
}

async getToken(code: string) {
const data = JSON.parse(Buffer.from(code, 'base64').toString());
const status = await client.lookupSigner({signerUuid: data.signer_uuid});
if (status.status === 'approved') {
return data.signer_uuid;
}

return '';
}

async getUser(providerToken: string) {
const status = await client.lookupSigner({signerUuid: providerToken});
if (status.status !== 'approved') {
return {
id: '',
email: '',
};
}


// const { client, oauth2 } = clientAndYoutube();
// client.setCredentials({ access_token: providerToken });
// const user = oauth2(client);
// const { data } = await user.userinfo.get();

return {
id: String('farcaster_' + status.fid),
email: String('farcaster_' + status.fid),
};
}
}
3 changes: 3 additions & 0 deletions apps/backend/src/services/auth/providers/providers.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Provider } from '@prisma/client';
import { GithubProvider } from '@gitroom/backend/services/auth/providers/github.provider';
import { ProvidersInterface } from '@gitroom/backend/services/auth/providers.interface';
import { GoogleProvider } from '@gitroom/backend/services/auth/providers/google.provider';
import { FarcasterProvider } from '@gitroom/backend/services/auth/providers/farcaster.provider';

export class ProvidersFactory {
static loadProvider(provider: Provider): ProvidersInterface {
Expand All @@ -10,6 +11,8 @@ export class ProvidersFactory {
return new GithubProvider();
case Provider.GOOGLE:
return new GoogleProvider();
case Provider.FARCASTER:
return new FarcasterProvider();
}
}
}
2 changes: 1 addition & 1 deletion apps/frontend/src/app/auth/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default async function AuthLayout({
<div className="absolute top-0 bg-gradient-to-t from-customColor9 w-[1px] translate-x-[22px] h-full" />
</div>
<div>
<div className="absolute right-0 bg-gradient-to-l from-customColor9 h-[1px] translate-y-[22px] w-full" />
<div className="absolute right-0 bg-gradient-to-l from-customColor9 h-[1px] translate-y-[60px] w-full" />
</div>
</div>
<div className="absolute top-0 bg-gradient-to-t from-customColor9 w-[1px] -translate-x-[22px] h-full" />
Expand Down
1 change: 1 addition & 0 deletions apps/frontend/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
uploadDirectory={process.env.NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY!}
tolt={process.env.NEXT_PUBLIC_TOLT!}
facebookPixel={process.env.NEXT_PUBLIC_FACEBOOK_PIXEL!}
neynarClientId={process.env.NEYNAR_CLIENT_ID!}

Check warning

Code scanning / ESLint

Disallow non-null assertions using the `!` postfix operator Warning

Forbidden non-null assertion.

Copilot Autofix AI 5 days ago

To fix the problem, we need to handle the potential null or undefined value of process.env.NEYNAR_CLIENT_ID explicitly. One way to do this is to provide a default value or throw an error if the value is not defined. This ensures that the application does not crash unexpectedly and that the developer is aware of the missing environment variable.

In this case, we can use a default value or throw an error if process.env.NEYNAR_CLIENT_ID is not defined. For example, we can use the ?? (nullish coalescing) operator to provide a default value or use a conditional check to throw an error.

Suggested changeset 1
apps/frontend/src/app/layout.tsx

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/apps/frontend/src/app/layout.tsx b/apps/frontend/src/app/layout.tsx
--- a/apps/frontend/src/app/layout.tsx
+++ b/apps/frontend/src/app/layout.tsx
@@ -44,3 +44,3 @@
           facebookPixel={process.env.NEXT_PUBLIC_FACEBOOK_PIXEL!}
-          neynarClientId={process.env.NEYNAR_CLIENT_ID!}
+          neynarClientId={process.env.NEYNAR_CLIENT_ID ?? (() => { throw new Error('NEYNAR_CLIENT_ID is not defined'); })()}
         >
EOF
@@ -44,3 +44,3 @@
facebookPixel={process.env.NEXT_PUBLIC_FACEBOOK_PIXEL!}
neynarClientId={process.env.NEYNAR_CLIENT_ID!}
neynarClientId={process.env.NEYNAR_CLIENT_ID ?? (() => { throw new Error('NEYNAR_CLIENT_ID is not defined'); })()}
>
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
>
<ToltScript />
<FacebookComponent />
Expand Down
18 changes: 15 additions & 3 deletions apps/frontend/src/components/auth/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { GithubProvider } from '@gitroom/frontend/components/auth/providers/gith
import interClass from '@gitroom/react/helpers/inter.font';
import { GoogleProvider } from '@gitroom/frontend/components/auth/providers/google.provider';
import { useVariables } from '@gitroom/react/helpers/variable.context';
import { FarcasterProvider } from '@gitroom/frontend/components/auth/providers/farcaster.provider';

type Inputs = {
email: string;
Expand All @@ -22,7 +23,7 @@ type Inputs = {

export function Login() {
const [loading, setLoading] = useState(false);
const {isGeneral} = useVariables();
const { isGeneral, neynarClientId } = useVariables();
const resolver = useMemo(() => {
return classValidatorResolver(LoginUserDto);
}, []);
Expand Down Expand Up @@ -62,7 +63,14 @@ export function Login() {
</h1>
</div>

{!isGeneral ? <GithubProvider /> : <GoogleProvider />}
{!isGeneral ? (
<GithubProvider />
) : (
<div className="gap-[5px] flex flex-col">
<GoogleProvider />
{!!neynarClientId && <FarcasterProvider />}
</div>
)}
<div className="h-[20px] mb-[24px] mt-[24px] relative">
<div className="absolute w-full h-[1px] bg-fifth top-[50%] -translate-y-[50%]" />
<div
Expand All @@ -89,7 +97,11 @@ export function Login() {
</div>
<div className="text-center mt-6">
<div className="w-full flex">
<Button type="submit" className="flex-1 rounded-[4px]" loading={loading}>
<Button
type="submit"
className="flex-1 rounded-[4px]"
loading={loading}
>
Sign in
</Button>
</div>
Expand Down
100 changes: 100 additions & 0 deletions apps/frontend/src/components/auth/nayner.auth.button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
'use client';

import React, {
useCallback,
useEffect,
useState,
useRef,
FC,
ReactNode,
} from 'react';
import { useNeynarContext } from '@neynar/react';

export const NeynarAuthButton: FC<{
children: ReactNode;
onLogin: (code: string) => void;
}> = (props) => {
const { children, onLogin } = props;
const { client_id } = useNeynarContext();

const [showModal, setShowModal] = useState(false);

const authWindowRef = useRef<Window | null>(null);
const neynarLoginUrl = `${
process.env.NEYNAR_LOGIN_URL ?? 'https://app.neynar.com/login'
}?client_id=${client_id}`;
const authOrigin = new URL(neynarLoginUrl).origin;

const modalRef = useRef<HTMLDivElement>(null);

const handleMessage = useCallback(
async (event: MessageEvent) => {
if (
event.origin === authOrigin &&
event.data &&
event.data.is_authenticated
) {
authWindowRef.current?.close();
window.removeEventListener('message', handleMessage); // Remove listener here
const _user = {
signer_uuid: event.data.signer_uuid,
...event.data.user,
};

onLogin(Buffer.from(JSON.stringify(_user)).toString('base64'));
}
},
[client_id, onLogin]

Check warning

Code scanning / ESLint

verifies the list of dependencies for Hooks like useEffect and similar Warning

React Hook useCallback has a missing dependency: 'authOrigin'. Either include it or remove the dependency array.
);

const handleSignIn = useCallback(() => {
const width = 600,
height = 700;
const left = window.screen.width / 2 - width / 2;
const top = window.screen.height / 2 - height / 2;
const windowFeatures = `width=${width},height=${height},top=${top},left=${left}`;

authWindowRef.current = window.open(
neynarLoginUrl,
'_blank',
windowFeatures
);

if (!authWindowRef.current) {
console.error(
'Failed to open the authentication window. Please check your pop-up blocker settings.'
);
return;
}

window.addEventListener('message', handleMessage, false);
}, [client_id, handleMessage]);

Check warning

Code scanning / ESLint

verifies the list of dependencies for Hooks like useEffect and similar Warning

React Hook useCallback has a missing dependency: 'neynarLoginUrl'. Either include it or remove the dependency array.

const closeModal = () => setShowModal(false);

useEffect(() => {
return () => {
window.removeEventListener('message', handleMessage); // Cleanup function to remove listener
};
}, [handleMessage]);

const handleOutsideClick = useCallback((event: any) => {
if (modalRef.current && !modalRef.current.contains(event.target)) {
closeModal();
}
}, []);

useEffect(() => {
if (showModal) {
document.addEventListener('mousedown', handleOutsideClick);
} else {
document.removeEventListener('mousedown', handleOutsideClick);
}

return () => {
document.removeEventListener('mousedown', handleOutsideClick);
};
}, [showModal, handleOutsideClick]);

return <div onClick={handleSignIn}>{children}</div>;
};
51 changes: 51 additions & 0 deletions apps/frontend/src/components/auth/providers/farcaster.provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useCallback } from 'react';
import interClass from '@gitroom/react/helpers/inter.font';
import { useVariables } from '@gitroom/react/helpers/variable.context';
import { NeynarContextProvider, Theme, useNeynarContext } from '@neynar/react';

Check warning

Code scanning / ESLint

Disallow unused variables Warning

'useNeynarContext' is defined but never used.

Copilot Autofix AI 5 days ago

To fix the problem, we need to remove the unused import useNeynarContext from the file. This will resolve the ESLint error and clean up the code by removing unnecessary imports.

  • Open the file apps/frontend/src/components/auth/providers/farcaster.provider.tsx.
  • Locate the import statement on line 4.
  • Remove useNeynarContext from the import statement.
Suggested changeset 1
apps/frontend/src/components/auth/providers/farcaster.provider.tsx

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/apps/frontend/src/components/auth/providers/farcaster.provider.tsx b/apps/frontend/src/components/auth/providers/farcaster.provider.tsx
--- a/apps/frontend/src/components/auth/providers/farcaster.provider.tsx
+++ b/apps/frontend/src/components/auth/providers/farcaster.provider.tsx
@@ -3,3 +3,3 @@
 import { useVariables } from '@gitroom/react/helpers/variable.context';
-import { NeynarContextProvider, Theme, useNeynarContext } from '@neynar/react';
+import { NeynarContextProvider, Theme } from '@neynar/react';
 import { NeynarAuthButton } from '@gitroom/frontend/components/auth/nayner.auth.button';
EOF
@@ -3,3 +3,3 @@
import { useVariables } from '@gitroom/react/helpers/variable.context';
import { NeynarContextProvider, Theme, useNeynarContext } from '@neynar/react';
import { NeynarContextProvider, Theme } from '@neynar/react';
import { NeynarAuthButton } from '@gitroom/frontend/components/auth/nayner.auth.button';
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
import { NeynarAuthButton } from '@gitroom/frontend/components/auth/nayner.auth.button';
import { useRouter } from 'next/navigation';

Check warning

Code scanning / ESLint

Disallow unused variables Warning

'useRouter' is defined but never used.

Copilot Autofix AI 5 days ago

To fix the problem, we need to remove the unused useRouter import from the file. This will resolve the ESLint error and clean up the code by removing unnecessary imports.

  • Open the file apps/frontend/src/components/auth/providers/farcaster.provider.tsx.
  • Locate the import statement for useRouter on line 6.
  • Remove the line that imports useRouter.
Suggested changeset 1
apps/frontend/src/components/auth/providers/farcaster.provider.tsx

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/apps/frontend/src/components/auth/providers/farcaster.provider.tsx b/apps/frontend/src/components/auth/providers/farcaster.provider.tsx
--- a/apps/frontend/src/components/auth/providers/farcaster.provider.tsx
+++ b/apps/frontend/src/components/auth/providers/farcaster.provider.tsx
@@ -5,3 +5,3 @@
 import { NeynarAuthButton } from '@gitroom/frontend/components/auth/nayner.auth.button';
-import { useRouter } from 'next/navigation';
+
 
EOF
@@ -5,3 +5,3 @@
import { NeynarAuthButton } from '@gitroom/frontend/components/auth/nayner.auth.button';
import { useRouter } from 'next/navigation';


Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options

export const FarcasterProvider = () => {
const { neynarClientId } = useVariables();

const gotoLogin = useCallback(async (code: string) => {
window.location.href = `/auth?provider=FARCASTER&code=${code}`;
}, []);

return (
<NeynarContextProvider
settings={{
clientId: neynarClientId,
defaultTheme: Theme.Dark,
}}
>
<NeynarAuthButton onLogin={gotoLogin}>
<div
className={`cursor-pointer bg-[#855ECD] h-[44px] rounded-[4px] flex justify-center items-center text-white ${interClass} gap-[4px]`}
>
<svg
width="21px"
height="21px"
viewBox="0 0 1000 1000"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M257.778 155.556H742.222V844.445H671.111V528.889H670.414C662.554 441.677 589.258 373.333 500 373.333C410.742 373.333 337.446 441.677 329.586 528.889H328.889V844.445H257.778V155.556Z"
fill="white"
/>
<path
d="M128.889 253.333L157.778 351.111H182.222V746.667C169.949 746.667 160 756.616 160 768.889V795.556H155.556C143.283 795.556 133.333 805.505 133.333 817.778V844.445H382.222V817.778C382.222 805.505 372.273 795.556 360 795.556H355.556V768.889C355.556 756.616 345.606 746.667 333.333 746.667H306.667V253.333H128.889Z"
fill="white"
/>
<path
d="M675.556 746.667C663.282 746.667 653.333 756.616 653.333 768.889V795.556H648.889C636.616 795.556 626.667 805.505 626.667 817.778V844.445H875.556V817.778C875.556 805.505 865.606 795.556 853.333 795.556H848.889V768.889C848.889 756.616 838.94 746.667 826.667 746.667V351.111H851.111L880 253.333H702.222V746.667H675.556Z"
fill="white"
/>
</svg>
<div>Continue with Farcaster</div>
</div>
</NeynarAuthButton>
</NeynarContextProvider>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const GoogleProvider = () => {
/>
</svg>
</div>
<div>Sign in with Google</div>
<div>Continue with Google</div>
</div>
);
};
12 changes: 10 additions & 2 deletions apps/frontend/src/components/auth/register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { useFireEvents } from '@gitroom/helpers/utils/use.fire.events';
import { useVariables } from '@gitroom/react/helpers/variable.context';
import { useTrack } from '@gitroom/react/helpers/use.track';
import { TrackEnum } from '@gitroom/nestjs-libraries/user/track.enum';
import { FarcasterProvider } from '@gitroom/frontend/components/auth/providers/farcaster.provider';

type Inputs = {
email: string;
Expand Down Expand Up @@ -85,7 +86,7 @@ export function RegisterAfter({
token: string;
provider: string;
}) {
const { isGeneral } = useVariables();
const { isGeneral, neynarClientId } = useVariables();
const [loading, setLoading] = useState(false);
const router = useRouter();
const fireEvents = useFireEvents();
Expand Down Expand Up @@ -153,7 +154,14 @@ export function RegisterAfter({
</h1>
</div>
{!isAfterProvider &&
(!isGeneral ? <GithubProvider /> : <GoogleProvider />)}
(!isGeneral ? (
<GithubProvider />
) : (
<div className="gap-[5px] flex flex-col">
<GoogleProvider />
{!!neynarClientId && <FarcasterProvider />}
</div>
))}
{!isAfterProvider && (
<div className="h-[20px] mb-[24px] mt-[24px] relative">
<div className="absolute w-full h-[1px] bg-fifth top-[50%] -translate-y-[50%]" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,7 @@ enum Provider {
LOCAL
GITHUB
GOOGLE
FARCASTER
}

enum Role {
Expand Down
4 changes: 4 additions & 0 deletions libraries/nestjs-libraries/src/services/email.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ export class EmailService {
}

async sendEmail(to: string, subject: string, html: string, replyTo?: string) {
if (to.indexOf('@') === -1) {
return ;
}

if (!process.env.EMAIL_FROM_ADDRESS || !process.env.EMAIL_FROM_NAME) {
console.log(
'Email sender information not found in environment variables'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
export class NewsletterService {
static async register(email: string) {
if (!process.env.BEEHIIVE_API_KEY || !process.env.BEEHIIVE_PUBLICATION_ID || process.env.NODE_ENV === 'development') {
if (
!process.env.BEEHIIVE_API_KEY ||
!process.env.BEEHIIVE_PUBLICATION_ID ||
process.env.NODE_ENV === 'development' ||
email.indexOf('@') === -1
) {
return;
}
const body = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface VariableContextInterface {
discordUrl: string;
uploadDirectory: string;
facebookPixel: string;
neynarClientId: string;
tolt: string;
}
const VariableContext = createContext({
Expand All @@ -24,6 +25,7 @@ const VariableContext = createContext({
discordUrl: '',
uploadDirectory: '',
facebookPixel: '',
neynarClientId: '',
tolt: '',
} as VariableContextInterface);

Expand Down
Loading