Skip to content

Commit

Permalink
Merge pull request #40 from CudoVentures/CUDOS-2316-fixing-Twitter-lo…
Browse files Browse the repository at this point in the history
…gin-issues

Cudos 2316 fixing twitter login issues
  • Loading branch information
mlukanova authored Feb 27, 2023
2 parents be60942 + 737a658 commit 331c4aa
Show file tree
Hide file tree
Showing 15 changed files with 699 additions and 60 deletions.
3 changes: 2 additions & 1 deletion apps/backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { UserController } from './user/user.controller';
import { DiscordService } from './discord/discord.service';
import { DiscordModule } from './discord/discord.module';
import { DiscordController } from './discord/discord.controller';
import { WebsocketGateway } from './websocket/websocket.gateway';

@Module({
imports: [
Expand Down Expand Up @@ -68,7 +69,7 @@ import { DiscordController } from './discord/discord.controller';
AllowlistModule,
DiscordModule
],
providers: [AppService, AuthService, UserService, AllowlistService, DiscordService],
providers: [AppService, AuthService, UserService, AllowlistService, DiscordService, WebsocketGateway],
controllers: [AuthController, AllowlistController, UserController, DiscordController],
})

Expand Down
13 changes: 12 additions & 1 deletion apps/backend/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@ import { AuthService } from './auth.service';
import { DiscordAuthGuard } from './guards/discord-auth.guard';
import { TwitterAuthGuard } from './guards/twitter-auth.guard';
import { DiscordService } from '../discord/discord.service';
import { WebsocketGateway } from '../websocket/websocket.gateway';
import { WS_MSGS, WS_ROOM } from 'apps/common/interfaces';

@ApiTags('Auth')
@Controller('auth')
export class AuthController {
constructor(
private authService: AuthService,
private discordService: DiscordService
private discordService: DiscordService,
private websocketGateway: WebsocketGateway
) { }

@UseInterceptors(TransactionInterceptor)
Expand Down Expand Up @@ -65,6 +68,10 @@ export class AuthController {
discord: user
}
}
this.websocketGateway.sendMessageToClient(
WS_ROOM.socialMediaEvents,
WS_MSGS.socialMediaSuccess
)
res.send(`<script>window.close()</script>`);
}

Expand All @@ -87,6 +94,10 @@ export class AuthController {
} else {
req.session.user = { twitter: req.user }
}
this.websocketGateway.sendMessageToClient(
WS_ROOM.socialMediaEvents,
WS_MSGS.socialMediaSuccess
)
res.send(`<script>window.close()</script>`);
}
}
3 changes: 2 additions & 1 deletion apps/backend/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { PassportModule } from '@nestjs/passport';
import { DiscordModule } from '../discord/discord.module';
import { UserModule } from '../user/user.module';
import { UserService } from '../user/user.service';
import { WebsocketGateway } from '../websocket/websocket.gateway';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { DiscordStrategy } from './strategies/discord.strategy';
import { TwitterStrategy } from './strategies/twitter.strategy';

@Module({
imports: [UserModule, PassportModule, DiscordModule],
providers: [AuthService, DiscordStrategy, TwitterStrategy, UserService],
providers: [AuthService, DiscordStrategy, TwitterStrategy, UserService, WebsocketGateway],
controllers: [AuthController],
exports: [AuthService],
})
Expand Down
12 changes: 11 additions & 1 deletion apps/backend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,17 @@ async function bootstrap() {
logger: console
});

app.enableCors();

app.enableCors({
origin: (origin, callback) => {
const whitelist = [process.env.APP_URL, process.env.AURA_POOL_URL]
if (origin === undefined || whitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
});

app.setGlobalPrefix('api');
app.enableVersioning({
Expand Down
1 change: 0 additions & 1 deletion apps/backend/src/user/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export class UserController {
async getUser(@Req() req) {
let twitterUser: UserEntity
let discordUser: UserEntity
console.log(req.session.user)
if (req.session.user?.twitter) {
twitterUser = await this.userService.findByTwitterId(req.session.user.twitter.twitter_profile_id)
}
Expand Down
74 changes: 74 additions & 0 deletions apps/backend/src/websocket/websocket.gateway.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { WebSocketGateway, WebSocketServer, OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect } from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { SubscribeMessage } from '@nestjs/websockets';
import { WS_MSGS, WS_ROOM } from '../../../common/interfaces';
import { UserService } from '../user/user.service';

@WebSocketGateway()
export class WebsocketGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
@WebSocketServer() server: Server;
constructor(private userService: UserService) { }

private connectedClients = new Set<string>();

private async isValidFeClient(client: Socket): Promise<{ isValid: boolean, user: string }> {
const incomingId = this.decodedId(client.handshake.query.customId)
const userAddress = incomingId.split(process.env.APP_WS_ID).pop();
const userFound = await this.userService.findByAddress(userAddress)
return { isValid: !!userFound && incomingId.startsWith(process.env.APP_WS_ID), user: userFound.address }
}

private decodedId(encodedString: any) {
return Buffer.from(encodedString, 'base64').toString('utf-8')
}

async handleConnection(client: Socket) {
const { isValid, user } = await this.isValidFeClient(client)

if (!isValid) {
client.disconnect(true)
console.log(`Socket Connection refused. Invalid client. Disconnecting...`);
return
}

if (this.connectedClients.has(user)) {
console.log(`Client ${user} - already connected. Disconnecting...`);
client.disconnect()
return
}

this.connectedClients.add(user);
console.log(`Client connected - ${user}`);

setTimeout(() => {
client.disconnect(true)
console.log(`Client ${user} disconnected - time out`);
}, 60000);
}

async handleDisconnect(client: Socket) {
const { user } = await this.isValidFeClient(client)
this.connectedClients.delete(user);
console.log(`Client ${user} disconnected`);
}

async afterInit(_: Server) {
console.log('WebSocket server initialized');
}

@SubscribeMessage(WS_MSGS.join)
async join(client: Socket, payload: any): Promise<void> {
const { isValid, user } = await this.isValidFeClient(client)
const roomName = payload.roomName;
if (isValid && roomName === WS_ROOM.socialMediaEvents) {
client.join(roomName);
console.log(`Client ${user} joined ${roomName}`);
return
}
client.disconnect(true)
}

sendMessageToClient(room: WS_ROOM, message: WS_MSGS, type?: any) {
this.server.to(room).emit(type ? type : message, message);
}
}
9 changes: 9 additions & 0 deletions apps/common/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ export enum SOCIAL_MEDIA {
discord = 'discord'
}

export enum WS_MSGS {
join = 'join',
socialMediaSuccess = 'socialMediaSuccess',
}

export enum WS_ROOM {
socialMediaEvents = 'socialMediaEvents'
}

export const emptySocialMedia = {
id: '',
userName: '',
Expand Down
37 changes: 37 additions & 0 deletions apps/frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { isExtensionEnabled, SUPPORTED_WALLET } from 'cudosjs';
import { useDispatch } from 'react-redux';
import io, { Socket } from 'socket.io-client';
import { DefaultEventsMap } from 'socket.io/dist/typed-events';

import theme from './core/theme';
import Layout from './core/presentation/components/Layout';
Expand All @@ -19,6 +21,34 @@ import { updateModalState } from './core/store/modals';
import { connectUser } from './features/wallets/helpers';
import { updateUser } from './core/store/user';
import useSocialMedia from './core/utilities/CustomHooks/useSocialMedia';
import { WS_MSGS, WS_ROOM } from '../../common/interfaces';

declare let Config: { APP_WS_ID: any, APP_URL: any };

export let socketConnection: Socket<DefaultEventsMap, DefaultEventsMap>;

export const disconnectSocket = () => {
if (socketConnection && socketConnection.connected) {
socketConnection.disconnect()
}
}

export const connectSocket = async (userAddres: string, setMedia: () => Promise<void>) => {
if (!socketConnection || socketConnection.disconnected) {
socketConnection = io(Config.APP_URL, {
query: { customId: Buffer.from(Config.APP_WS_ID + userAddres).toString('base64') }
});

socketConnection.on('connect', () => {
socketConnection.emit(WS_MSGS.join, { roomName: WS_ROOM.socialMediaEvents });
});

socketConnection.on(WS_MSGS.socialMediaSuccess, async () => {
await setMedia()
disconnectSocket()
});
}
}

const App = () => {

Expand Down Expand Up @@ -59,6 +89,13 @@ const App = () => {
}
}, [reconnectUser])

useEffect(() => {
//Clean-up on app closing
return () => {
disconnectSocket()
};
}, []);

return (
<Fragment>
<LocalizationProvider dateAdapter={AdapterMoment}>
Expand Down
26 changes: 9 additions & 17 deletions apps/frontend/src/core/utilities/CustomHooks/useSocialMedia.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { GET_USER_DETAILS, LOG_OUT_MEDIA_USER } from '../../api/calls';
import { ADD_DISCORD_BOT_URL, SOCIAL_MEDIA_LOGIN_URL } from '../../api/endpoints';
import { CONNECTED_SOCIAL_MEDIA, emptySocialMedia, SOCIAL_MEDIA } from '../../../../../common/interfaces';
import { updateUser } from '../../store/user';
import { connectSocket, disconnectSocket } from '../../../App';

const windowOptions = `toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=1,width=600, height=800,top=0`

Expand All @@ -26,41 +27,32 @@ const useSocialMedia = () => {
dispatch(updateUser({ connectedSocialMedia: media }))
}

const connectSocialMedia = async (service: SOCIAL_MEDIA) => {
const openedWindow = window.open(
const connectSocialMedia = async (userAddress: string, service: SOCIAL_MEDIA) => {
await connectSocket(userAddress, setConnectedSocialMedia)
window.open(
SOCIAL_MEDIA_LOGIN_URL(service),
`${service} Log In`,
windowOptions
)
const timer = setInterval(async () => {
if (openedWindow.closed) {
await setConnectedSocialMedia()
clearInterval(timer)
}
}, 1000)
}

const addDiscordBot = async () => {
const openedWindow = window.open(
const addDiscordBot = async (userAddress: string) => {
await connectSocket(userAddress, setConnectedSocialMedia)
window.open(
ADD_DISCORD_BOT_URL(Config.APP_DISCORD_CLIENT_ID, Config.APP_DISCORD_CALLBACK_URL),
`Adding Discord Bot`,
windowOptions
)

const timer = setInterval(async () => {
if (openedWindow.closed) {
await setConnectedSocialMedia()
clearInterval(timer)
}
}, 1000)
};

const disconnectSocialMedia = async (service: SOCIAL_MEDIA) => {
disconnectSocket()
await LOG_OUT_MEDIA_USER(service)
await setConnectedSocialMedia()
}

const disconnectAllSocialMedias = async () => {
disconnectSocket()
await LOG_OUT_MEDIA_USER(SOCIAL_MEDIA.discord)
await LOG_OUT_MEDIA_USER(SOCIAL_MEDIA.twitter)
dispatch(updateUser({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const RegistrationCriteriaForm = (): JSX.Element => {
if (e.target.value === 'discord_server') {

if (e.target.checked) {
addDiscordBot()
addDiscordBot(connectedAddress)
} else {
dispatch(updateUser({
connectedSocialMedia: {
Expand All @@ -78,7 +78,7 @@ const RegistrationCriteriaForm = (): JSX.Element => {
disabled={!connectedAddress}
variant="contained"
sx={{ height: '38px', width: '104px' }}
onClick={() => connectSocialMedia(SOCIAL_MEDIA.twitter)}
onClick={() => connectSocialMedia(connectedAddress, SOCIAL_MEDIA.twitter)}
>
Connect
</Button>
Expand All @@ -89,7 +89,7 @@ const RegistrationCriteriaForm = (): JSX.Element => {
disabled={!connectedAddress}
variant="contained"
sx={{ height: '38px', width: '104px' }}
onClick={() => connectSocialMedia(SOCIAL_MEDIA.discord)}
onClick={() => connectSocialMedia(connectedAddress, SOCIAL_MEDIA.discord)}
>
Connect
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export const onChange = (e: any, stateFunc: React.Dispatch<React.SetStateAction<
export const SocialMediaButtons = () => {

const { connectSocialMedia, disconnectSocialMedia } = useSocialMedia()
const { connectedSocialMedia } = useSelector((state: RootState) => state.userState)
const { connectedSocialMedia, connectedAddress } = useSelector((state: RootState) => state.userState)

const StyledTypography = ({ type, media }: { type: LAYOUT_CONTENT_TEXT, media: SOCIAL_MEDIA }) => {
const [openMenu, setOpenMenu] = useState<boolean>(false)
Expand All @@ -119,7 +119,7 @@ export const SocialMediaButtons = () => {
fontWeight={700}
sx={{ minWidth: 'max-content', minHeight: 'max-content', cursor: 'pointer', display: 'flex', alignItems: 'center' }}
onMouseOver={() => isDisconnected ? null : setOpenMenu(true)}
onClick={() => isDisconnected ? connectSocialMedia(media) : null}
onClick={() => isDisconnected ? connectSocialMedia(connectedAddress, media) : null}
>
<SvgComponent
type={type}
Expand Down Expand Up @@ -243,7 +243,7 @@ export const SocialMediaBoxes = ({
disabled={!connectedAddress}
variant="contained"
sx={{ height: '40px', width: '104px' }}
onClick={() => connectSocialMedia(SOCIAL_MEDIA.twitter)}
onClick={() => connectSocialMedia(connectedAddress, SOCIAL_MEDIA.twitter)}
>
Connect
</Button>}
Expand Down Expand Up @@ -317,7 +317,7 @@ export const SocialMediaBoxes = ({
disabled={!connectedAddress}
variant="contained"
sx={{ height: '40px', width: '104px' }}
onClick={() => connectSocialMedia(SOCIAL_MEDIA.discord)}
onClick={() => connectSocialMedia(connectedAddress, SOCIAL_MEDIA.discord)}
>
Connect
</Button>}
Expand Down
3 changes: 3 additions & 0 deletions apps/frontend/src/features/wallets/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { connectCosmostationLedger } from "./Cosmostation"
import { connectKeplrLedger } from "./Keplr"
import { LAYOUT_CONTENT_TEXT, SvgComponent } from "../../core/presentation/components/Layout/helpers"
import { LOG_IN_USER } from "../../core/api/calls"
import { connectSocket, disconnectSocket, socketConnection } from "../../App"

import { styles } from "./styles"

Expand Down Expand Up @@ -120,6 +121,8 @@ export const connectUser = async (walletType: SUPPORTED_WALLET): Promise<userSta

export const disconnectWalletByType = async (walletType: SUPPORTED_WALLET) => {

disconnectSocket()

if (walletType === SUPPORTED_WALLET.Keplr) {
// Keplr seems to not offer a particular disconnect method
return
Expand Down
Loading

0 comments on commit 331c4aa

Please sign in to comment.