diff --git a/index.ts b/index.ts index 155aab8..efb463b 100644 --- a/index.ts +++ b/index.ts @@ -11,3 +11,4 @@ export { telegramCleanReplyMarkup } from "./src/functions/telegram_clean_reply_m export { telegramMembersMute } from "./src/functions/telegram_members_mute"; export { telegramMembersUnmute } from "./src/functions/telegram_members_unmute"; export { telegramPublicWebhook } from "./src/functions/telegram_public_webhook"; +export { telegramGetMessages } from "./src/functions/telegram_get_messages"; diff --git a/mock_events/event_telegram_authorizer.json b/mock_events/event_telegram_authorizer.json index d10ced2..baa164a 100644 --- a/mock_events/event_telegram_authorizer.json +++ b/mock_events/event_telegram_authorizer.json @@ -1,3 +1,3 @@ { - "authorizationToken": "Basic S0dSYWZ2eVNxSTBoSm5vQVZuOHFqZzFRRkp3WEg4cFI6OjEyTUd6alhmeENEMmVTbGR3azdabXNiUWlRTHN6OTY1ZFhyZFJSSS0yR1U5V2kzdVpvLVY4bmN5Y3JFVEZLbEk=" + "authorizationToken": "Basic MTM0NjU1NzA4NToyMmYzOTFkNS0xODcyLTRhZmItYTIxMS1hYjNiYmEyNGRlNjk=" } diff --git a/serverless.yml b/serverless.yml index fbc5372..13cba93 100644 --- a/serverless.yml +++ b/serverless.yml @@ -24,6 +24,8 @@ provider: MONGO_PASSWORD: ${self:custom.secrets.provider.environment.MONGO_PASSWORD} MONGO_HOST: ${self:custom.secrets.provider.environment.MONGO_HOST} MONGO_DATABASE: ${self:custom.secrets.provider.environment.MONGO_DATABASE} + USERNAME: ${self:custom.secrets.provider.environment.USERNAME} + PASSWORD: ${self:custom.secrets.provider.environment.PASSWORD} functions: telegramAuthorizer: ${file(./src/functions/telegram_authorizer/function.yml)} @@ -39,3 +41,4 @@ functions: telegramMembersMute: ${file(./src/functions/telegram_members_mute/function.yml)} telegramMembersUnmute: ${file(./src/functions/telegram_members_unmute/function.yml)} telegramPublicWebhook: ${file(./src/functions/telegram_public_webhook/function.yml)} + telegramGetAllMessages: ${file(./src/functions/telegram_get_messages/function.yml)} diff --git a/src/functions/telegram_authorizer/index.ts b/src/functions/telegram_authorizer/index.ts index 284e1b4..177e990 100644 --- a/src/functions/telegram_authorizer/index.ts +++ b/src/functions/telegram_authorizer/index.ts @@ -2,7 +2,7 @@ import { APIGatewayAuthorizerResult, APIGatewayTokenAuthorizerEvent, } from "aws-lambda"; -import { AuthService } from "../../lib/services"; +import { UserDao } from "../../lib/dao/userDao"; enum Effect { DENY = "Deny", @@ -33,20 +33,20 @@ const extractToken = (authorizationToken: string) => { const [_, token] = authorizationToken?.split(" "); const cleanToken = atob(token); const [clientId, clientSecret] = cleanToken?.split(":"); + console.log("extractToken", `${clientId}, ${clientSecret}`); return { clientId, clientSecret }; }; -const loginToAuth0 = async ( - clientId: string | number, - clientSecret: string | number +const login = async ( + clientId: string, + clientSecret: string ): Promise => { try { - AuthService.initInstance(); - await AuthService.getToken(clientId, clientSecret); - return Effect.ALLOW; + await UserDao.initInstance(); + const user = await UserDao.findByKey(clientId, clientSecret); + return Boolean(user) ? Effect.ALLOW : Effect.DENY; } catch (error) { - console.log(`${Effect.DENY}: ${error.message}`, error); - return Effect.ALLOW; + return Effect.DENY; } }; @@ -54,12 +54,10 @@ export const telegramAuthorizer = async ( event: APIGatewayTokenAuthorizerEvent ): Promise => { if (!event?.authorizationToken) { - console.log(`Effect: ${Effect.DENY}`); return buildPolicy(event.methodArn, Effect.DENY); } const { clientId, clientSecret } = extractToken(event.authorizationToken); - const effect = await loginToAuth0(clientId, clientSecret); - console.log(`Effect: ${effect}`); + const effect = await login(clientId, clientSecret); return buildPolicy(event.methodArn, effect); }; diff --git a/src/functions/telegram_get_messages/function.yml b/src/functions/telegram_get_messages/function.yml new file mode 100644 index 0000000..7631799 --- /dev/null +++ b/src/functions/telegram_get_messages/function.yml @@ -0,0 +1,13 @@ +name: ${self:custom.secrets.service.name}-${self:custom.secrets.provider.stage}-telegram-get-messages +handler: index.telegramGetMessages +memorySize: 128 +timeout: 30 +reservedConcurrency: 5 +events: + - http: + path: /${self:custom.secrets.service.name}-${self:custom.secrets.provider.stage}/telegram/get-messages + method: GET + cors: true + authorizer: + name: telegramAuthorizer + resultTtlInSeconds: 0 diff --git a/src/functions/telegram_get_messages/index.ts b/src/functions/telegram_get_messages/index.ts new file mode 100644 index 0000000..3e8dace --- /dev/null +++ b/src/functions/telegram_get_messages/index.ts @@ -0,0 +1,28 @@ +import { APIGatewayEvent, Callback, Context } from "aws-lambda"; +import { BAD_REQUEST, OK } from "http-status"; +import { ChatMessageDao } from "../../lib/dao"; + +const execute = async (event: APIGatewayEvent): Promise => { + if (!event?.queryStringParameters?.chat_id) { + return { statusCode: BAD_REQUEST }; + } + + const chatId = Number(event.queryStringParameters.chat_id); + + await ChatMessageDao.initInstance(); + const messages = await ChatMessageDao.getAll(chatId); + + return { statusCode: OK, body: JSON.stringify(messages) }; +}; + +export const telegramGetMessages = async ( + event: APIGatewayEvent, + context: Context, + callback: Callback +): Promise => { + context.callbackWaitsForEmptyEventLoop = false; + + const response = await execute(event); + + return callback(null, response); +}; diff --git a/src/functions/telegram_public_webhook/function.yml b/src/functions/telegram_public_webhook/function.yml index b8c124d..49a8125 100644 --- a/src/functions/telegram_public_webhook/function.yml +++ b/src/functions/telegram_public_webhook/function.yml @@ -8,3 +8,6 @@ events: path: /${self:custom.secrets.service.name}-${self:custom.secrets.provider.stage}/telegram/public-webhook method: POST cors: true + authorizer: + name: telegramAuthorizer + resultTtlInSeconds: 0 diff --git a/src/functions/telegram_public_webhook/index.ts b/src/functions/telegram_public_webhook/index.ts index c1e7094..5b953cd 100644 --- a/src/functions/telegram_public_webhook/index.ts +++ b/src/functions/telegram_public_webhook/index.ts @@ -1,7 +1,6 @@ import { APIGatewayEvent, Callback, Context } from "aws-lambda"; -import { OK, BAD_REQUEST, UNAUTHORIZED } from "http-status"; +import { OK, BAD_REQUEST } from "http-status"; import { TelegramService } from "../../lib/services"; -import { UserDao } from "../../lib/dao"; import { FormattingOptionsTg } from "../../lib/models"; interface PublicWebhookParams { @@ -13,26 +12,6 @@ interface PublicWebhookParams { media_is_spoiler?: boolean; } -const checkAuthorization = async (event: APIGatewayEvent) => { - if ( - !event?.queryStringParameters?.id || - !event?.queryStringParameters?.username - ) { - return false; - } - - const { id, username } = event?.queryStringParameters; - - await UserDao.initInstance(); - - try { - const user = await UserDao.findByIdAndUsername(id, username); - return Boolean(user); - } catch (_error) { - return false; - } -}; - const buildText = (body: PublicWebhookParams): string | undefined => { if (!body?.text) { return; @@ -138,11 +117,6 @@ export const telegramPublicWebhook = async ( ): Promise => { context.callbackWaitsForEmptyEventLoop = false; - const checkAuth = await checkAuthorization(event); - if (!checkAuth) { - return callback(null, { statusCode: UNAUTHORIZED }); - } - if (!event?.body) { return callback(null, { statusCode: BAD_REQUEST }); } diff --git a/src/functions/telegram_send_message/function.yml b/src/functions/telegram_send_message/function.yml index 39c9115..7a19a7f 100644 --- a/src/functions/telegram_send_message/function.yml +++ b/src/functions/telegram_send_message/function.yml @@ -8,3 +8,6 @@ events: path: /${self:custom.secrets.service.name}-${self:custom.secrets.provider.stage}/telegram/send-message method: POST cors: true + authorizer: + name: telegramAuthorizer + resultTtlInSeconds: 0 diff --git a/src/functions/telegram_send_photo/function.yml b/src/functions/telegram_send_photo/function.yml index 017cd21..416a94b 100644 --- a/src/functions/telegram_send_photo/function.yml +++ b/src/functions/telegram_send_photo/function.yml @@ -8,3 +8,6 @@ events: path: /${self:custom.secrets.service.name}-${self:custom.secrets.provider.stage}/telegram/send-photo method: POST cors: true + authorizer: + name: telegramAuthorizer + resultTtlInSeconds: 0 diff --git a/src/functions/telegram_send_video/function.yml b/src/functions/telegram_send_video/function.yml index 834519f..c6eb5e1 100644 --- a/src/functions/telegram_send_video/function.yml +++ b/src/functions/telegram_send_video/function.yml @@ -8,3 +8,6 @@ events: path: /${self:custom.secrets.service.name}-${self:custom.secrets.provider.stage}/telegram/send-video method: POST cors: true + authorizer: + name: telegramAuthorizer + resultTtlInSeconds: 0 diff --git a/src/functions/telegram_set_webhook/function.yml b/src/functions/telegram_set_webhook/function.yml index 81ed28a..5fb9e09 100644 --- a/src/functions/telegram_set_webhook/function.yml +++ b/src/functions/telegram_set_webhook/function.yml @@ -8,3 +8,6 @@ events: path: /${self:custom.secrets.service.name}-${self:custom.secrets.provider.stage}/telegram/set-webhook method: POST cors: true + authorizer: + name: telegramAuthorizer + resultTtlInSeconds: 0 diff --git a/src/functions/telegram_webhook/index.ts b/src/functions/telegram_webhook/index.ts index 739a2bd..ba82cbe 100644 --- a/src/functions/telegram_webhook/index.ts +++ b/src/functions/telegram_webhook/index.ts @@ -3,7 +3,7 @@ import { OK, BAD_REQUEST, NO_CONTENT } from "http-status"; import axios from "axios"; import { getTextCommand } from "../../lib/utils/telegramHelper"; import { Command, UpdateTg, User, FormattingOptionsTg } from "../../lib/models"; -import { CommandDao, UserDao } from "../../lib/dao"; +import { CommandDao, UserDao, ChatMessageDao } from "../../lib/dao"; import { TelegramService } from "../../lib/services"; const { STAGE } = process.env; @@ -21,6 +21,11 @@ const getCommand = async (body: UpdateTg): Promise => { return CommandDao.findByKey(key); }; +const saveChatMessage = async (body: UpdateTg): Promise => { + await ChatMessageDao.initInstance(); + await ChatMessageDao.save({ telegramMessage: body, expireAt: new Date() }); +}; + const request = async (command: Command, body: UpdateTg) => { try { console.log(`${command.key}: ${command.url}`); @@ -115,6 +120,9 @@ export const telegramWebhook = async ( if (STAGE === "dev") { console.log(`webhook message: \n${JSON.stringify(body, null, 2)} `); } + + await saveChatMessage(body); + const response = await execute(body); const endDate = new Date(); diff --git a/src/lib/dao/chatMessageDao.ts b/src/lib/dao/chatMessageDao.ts new file mode 100644 index 0000000..ae1d513 --- /dev/null +++ b/src/lib/dao/chatMessageDao.ts @@ -0,0 +1,52 @@ +import { Model, Schema, model } from "mongoose"; +import { ChatMessage } from "../models"; +import { MongodbService } from "../services"; + +export class ChatMessageDao { + private static schemaName: string = "chat_message"; + private static chatMessageSchema: Schema; + public static chatMessageModel: Model; + + private constructor() {} + + public static async initInstance() { + await MongodbService.initInstance(); + + if (!ChatMessageDao.chatMessageSchema) { + ChatMessageDao.chatMessageSchema = new Schema( + { + telegramMessage: { type: Schema.Types.Mixed, required: true }, + expireAt: { type: Schema.Types.Date, expires: 43200 }, + }, + { + timestamps: true, + expireAfterSeconds: 43200, + } + ); + } + + if (!ChatMessageDao.chatMessageModel) { + ChatMessageDao.chatMessageModel = model( + ChatMessageDao.schemaName, + ChatMessageDao.chatMessageSchema + ); + } + } + + public static async save( + chatMessage: ChatMessage + ): Promise { + return ChatMessageDao.chatMessageModel.create(chatMessage); + } + + public static async getAll(chatId: Number): Promise> { + const chatMessages = await ChatMessageDao.chatMessageModel + .find({ "telegramMessage.message.chat.id": chatId }) + .exec(); + if (!chatMessages || !chatMessages?.length) { + return []; + } + + return chatMessages; + } +} diff --git a/src/lib/dao/index.ts b/src/lib/dao/index.ts index 14880e5..94879a8 100644 --- a/src/lib/dao/index.ts +++ b/src/lib/dao/index.ts @@ -1,2 +1,3 @@ export { CommandDao } from "./commandDao"; export { UserDao } from "./userDao"; +export { ChatMessageDao } from "./chatMessageDao"; diff --git a/src/lib/dao/userDao.ts b/src/lib/dao/userDao.ts index 45c183d..a02dbf7 100644 --- a/src/lib/dao/userDao.ts +++ b/src/lib/dao/userDao.ts @@ -75,6 +75,15 @@ export class UserDao { return null; } + public static async findByKey(id: string, key: string): Promise { + const document = await UserDao.userModel.findOne({ id, key }).exec(); + if (document) { + return { ...document.toObject() } as User; + } + + return null; + } + public static async save(user: User): Promise { if (!user?.id) { throw new Error("id is missing"); diff --git a/src/lib/models/botnorrea.ts b/src/lib/models/botnorrea.ts index 192b56a..38e49b4 100644 --- a/src/lib/models/botnorrea.ts +++ b/src/lib/models/botnorrea.ts @@ -1,3 +1,5 @@ +import { UpdateTg } from "./telegram"; + interface ID { $oid: string; } @@ -13,6 +15,7 @@ export interface User { firstname?: string; lastname?: string; qrPathId?: string; + key?: string; createdAt?: AtedAt | string; updatedAt?: AtedAt | string; } @@ -33,3 +36,11 @@ export interface Command { createdAt?: AtedAt | string; updatedAt?: AtedAt | string; } + +export interface ChatMessage { + _id?: ID | string; + telegramMessage: UpdateTg; + expireAt?: Date | AtedAt | string; + createdAt?: AtedAt | string; + updatedAt?: AtedAt | string; +} diff --git a/src/lib/models/index.ts b/src/lib/models/index.ts index 64d2fb2..aade6e4 100644 --- a/src/lib/models/index.ts +++ b/src/lib/models/index.ts @@ -1,4 +1,4 @@ -export { Command, Crew, User } from "./botnorrea"; +export { Command, Crew, User, ChatMessage } from "./botnorrea"; export { ChatTg, ChatTypeTg,