def get_tasks(chat_id): email_address = dc.get_email_address(chat_id) service = ac.get_gmail_service(email_address) before = datetime.date.today().strftime("%Y/%m/%d").replace("/0", "/") after = (datetime.date.today() + relativedelta(days=-3)).strftime("%y/%m/%d").replace("/0", "/") query = "from:(service@{}) subject:python after:{} before:{}".format( SERVICE_NAME, after, before) response = service.users().messages().list(userId="me", q=query).execute() messages = [] if 'messages' in response: messages.extend(response['messages']) while 'nextPageToken' in response: page_token = response['nextPageToken'] response = service.users().messages().list( userId="me", q=query, pageToken=page_token).execute() messages.extend(response['messages']) mime_msgs = [] for m in messages: mime_msgs.append(get_mime_msg(service, m["id"])) log_line("GF tasks were received!") return mime_msgs
def encrypt(data): log_line("Creds try encript!") cipher = AES.new(DB_KEY, AES.MODE_EAX) nonce = cipher.nonce cipher_text, tag = cipher.encrypt_and_digest(data) log_line("Creds encrypt_and_digest!") return cipher_text, tag, nonce
def change_latest_history_id(email_address, new_historyId): try: exec_data_manipulation_query( "UPDATE email_historyIds SET last_historyId = {} WHERE email = \'{}\'" .format(new_historyId, email_address)) except psycopg2.IntegrityError: log_line("Update was failed!") raise NotFoundException(email_address, "email", "email_historyIds")
def set_webhook(self): if not bool(self.bot.get_webhook_info().url): try: self.bot.setWebhook("https://{}.herokuapp.com/{}".format(NAME, TOKEN)) log_line("Webhook was set") except telegram.error.RetryAfter: log_line("telegram.error.RetryAfter WAS ENCOUNTERED :(") sleep(2) self.set_webhook()
def receive_email_notification(): response = request.get_json(force=True) encrypted_message_data = response["message"]["data"] message_data = json.loads(base64.b64decode(encrypted_message_data)) try: process_email_notification(message_data) except dc.NotFoundException: log_line("FAILED TO RECEIVE NOTIFICATION!") return "Unauthorized", 401 return "OK", 200
def decrypt(cipher_text, tag, nonce): cipher = AES.new(DB_KEY, AES.MODE_EAX, nonce=nonce) plaintext = cipher.decrypt(cipher_text) try: cipher.verify(tag) log_line("Decryption went fine!") return plaintext except ValueError: log_line("Decryption went wrong!") raise CipherException
def create_tables(): try: exec_data_manipulation_query( "CREATE TABLE email_credentials (email text, cipher_text bytea, tag bytea, nonce bytea, PRIMARY KEY (email))" ) # raise NotImplementedError # exec_data_manipulation_query("alter table email_historyIds add primary key ( email )") # exec_data_manipulation_query("alter table email_chats add primary key ( email )") except psycopg2.ProgrammingError: log_line("email_historyIds already exists!")
def repr_mime_msg(msg): mail_emoji = "\U00002709" body = "" for part in msg.walk(): if part.get_content_type() == "text/plain": body += part.get_payload(decode=True).decode("UTF-8") representation = ("From : {}{}\nSubject : {}\n{}\n" .format(mail_emoji, msg["From"], msg["Subject"], body)) # log_line(representation) log_line("Message representation was received!") return representation
def send_mime_msg(self, chat_id, mime_msg): text_msg = repr_mime_msg(mime_msg) if len(text_msg) > 4096: text_msg = "TEXT IS TOO LONG\n\n" + text_msg log_line("Mime message was TOO LONG!") while len(text_msg) > 0: self.bot.sendMessage(chat_id=chat_id, text=text_msg[:4000], disable_web_page_preview=True, parse_mode=telegram.ParseMode.MARKDOWN) text_msg = text_msg[4000:] self.bot.sendMessage(chat_id=chat_id, text=text_msg, disable_web_page_preview=True, parse_mode=telegram.ParseMode.MARKDOWN) log_line("Mime message was sent!")
def get_body(html=True): body = "" content_type = "text/html" if html else "text/plain" for part in mime_msg.walk(): if "multipart" not in part.get_content_type( ) and part.get_content_type() == content_type: body += "{}\n".format( part.get_payload(decode=True).decode("UTF-8")) if html: log_line("BODY : " + body) body = html2text.html2text(body) log_line("PARSED BODY : " + body) return body
def start_watch(email_address): service = get_gmail_service(email_address) topic_path = "projects/{}/topics/{}".format(GCP_PROJECT_NAME, GCP_TOPIC_NAME) gmail_request = {"labelIds": ["UNREAD"], "labelFilterAction": "include", "topicName": topic_path} service.users().stop(userId="me").execute() watch_res = service.users().watch(userId="me", body=gmail_request).execute() log_line("Result of watch : " + str(watch_res)) return watch_res
def process_email_notification(message_data): email_address = message_data["emailAddress"] start_history_id = dc.get_latest_historyId(email_address) chat_id = dc.get_chat_id(email_address) bot.send_message(chat_id=chat_id, text="You have received this historyId : " + str(message_data["historyId"])) # bot.send_message(chat_id=chat_id, # text="You have received these changes : " + str(changes)[:4000]) messages = gc.get_new_messages(email_address, start_history_id) for mime_msg in messages: bot.send_mime_msg(chat_id=chat_id, mime_msg=mime_msg) log_line("Email notification was processed!")
def store_credentials(email_address, credentials): log_line("Creds try store!") cipher_text, tag, nonce = encrypt(credentials) cipher_text, tag, nonce = [ psycopg2.Binary(data) for data in (cipher_text, tag, nonce) ] log_line("Creds encrypted!") try: exec_data_manipulation_query( "INSERT INTO email_credentials (email, cipher_text, tag, nonce) VALUES (\'{}\', {}, {}, {})" .format(email_address, cipher_text, tag, nonce)) log_line("User " + email_address + " was successfully added to email_credentials table!") except psycopg2.IntegrityError: log_line("email_credentials already contains " + email_address + " key!") except Exception as e: log_line(str(e) + " key!")
def exchange_code(authorization_code): """Exchange an authorization code for OAuth 2.0 credentials. Args: authorization_code: Authorization code to exchange for OAuth 2.0 credentials. Returns: oauth2client.client.OAuth2Credentials instance. Raises: CodeExchangeException: an error occurred. """ flow = OAuth2WebServerFlow(client_id=CLIENT_ID, client_secret=CLIENT_SECRET, scope=SCOPES) flow.redirect_uri = REDIRECT_URI try: credentials = flow.step2_exchange(authorization_code) return credentials except FlowExchangeError as err: log_line('An error occurred: ' + str(err)) raise CodeExchangeException(None)
def get_user_info(credentials): """Send a request to the UserInfo API to retrieve the user's information. Args: credentials: oauth2client.client.OAuth2Credentials instance to authorize the request. Returns: User information as a dict. """ user_info_service = build( serviceName='oauth2', version='v2', http=credentials.authorize(Http())) user_info = None try: user_info = user_info_service.userinfo().get().execute() except HttpError as e: log_line('An error occurred: ' + str(e)) if user_info and user_info.get('email'): return user_info else: raise NoUserInfoException()
def save_user(email_address, chat_id, base_history_id): try: exec_data_manipulation_query( "INSERT INTO email_chats (email, chat) VALUES (\'{}\', {})".format( email_address, chat_id)) log_line("User " + email_address + " was successfully added to email_chats table!") except psycopg2.IntegrityError: log_line("email_chats already contains " + email_address + " key!") try: exec_data_manipulation_query( "INSERT INTO email_historyIds (email, base_historyId, last_historyId) VALUES (\'{}\', {}, {})" .format(email_address, base_history_id, base_history_id)) log_line("User " + email_address + " was successfully added to email_historyIds table!") except psycopg2.IntegrityError: log_line("email_historyIds already contains " + email_address + " key!")
def start(bot, update, args): log_line("Started!") if args: code = ac.get_code(args[0]) if not code: update.effective_message.reply_text("What does " + ''.join(args) + " mean? Try again please!") log_line("Start parameters were wrong!") return log_line("Bot has received the key!") update.effective_message.reply_text("Hello there, Telegram user!") ac.authorize_user(code, update.effective_chat.id) else: # store = oauth_file.Storage(str(update.effective_user.id) + "_token.json") authorize_url = ac.get_authorization_url() update.effective_message.reply_text(authorize_url)
def store_credentials(email_address, credentials): """Store OAuth 2.0 credentials in the application's database. This function stores the provided OAuth 2.0 credentials using the user ID as key. Args: email_address: User's email address. credentials: OAuth 2.0 credentials to store. Raises: """ json_creds = credentials.to_json().encode() log_line("# 1" + str(type(json_creds))) log_line("# 2" + str(json_creds)) dc.store_credentials(email_address, json_creds) log_line("Creds stored!")
def get_credentials(authorization_code): """Retrieve credentials using the provided authorization code. This function exchanges the authorization code for an access token and queries the UserInfo API to retrieve the user's e-mail address. If a refresh token has been retrieved along with an access token, it is stored in the application database using the user's e-mail address as key. If no refresh token has been retrieved, the function checks in the application database for one and returns it if found or raises a NoRefreshTokenException with the authorization URL to redirect the user to. Args: authorization_code: Authorization code to use to retrieve an access token. Returns: oauth2client.client.OAuth2Credentials instance containing an access and refresh token. Raises: CodeExchangeError: Could not exchange the authorization code. NoRefreshTokenException: No refresh token could be retrieved from the available sources. """ try: credentials = exchange_code(authorization_code) email_address = get_user_info(credentials).get('email') log_line("Refresh token:" + str(credentials.refresh_token)) if credentials.refresh_token is not None: store_credentials(email_address, credentials) return credentials else: credentials = get_stored_credentials(email_address) if credentials and credentials.refresh_token is not None: return credentials except CodeExchangeException as err: log_line('An error occurred during code exchange.\n') # Drive apps should try to retrieve the user and credentials for the current session. # If none is available, redirect the user to the authorization URL. err.authorization_url = get_authorization_url() raise err except NoUserInfoException: log_line('No user info could be retrieved.\n') # No refresh token has been retrieved. authorization_url = get_authorization_url() raise NoRefreshTokenException(authorization_url)
def get_database_connection(): try: return psycopg2.connect(DATABASE_URL, sslmode='require') except: log_line("Unable to connect to database!")
def echo(bot, update): update.effective_message.reply_text(update.effective_message.text) log_line("Answered!")
def get_new_messages(email_address, start_history_id): gmail_service = ac.get_gmail_service(email_address) changes = get_changes(email_address, gmail_service, start_history_id) messages = get_msgs_from_changes(changes, gmail_service) log_line("New messages were received") return messages
def help_(bot, update): chat_id = update.effective_chat.id ac.renew_watch(chat_id) log_line("Watch was revoked!")
def error(bot, update, error_): log_line("Update {} caused error {}".format(str(update), str(error_)))
def webhook(): msg = request.get_json(force=True) bot.process_msg(msg) log_line("Message was processed") return "Hello there!"
def __init__(self, value, column, table): msg = "{} was not found in {} column of {} table!\n".format( value, column, table) super().__init__(msg) log_line(msg)