How to use phone_code parameter in pyrogram framework(python) - python

If you know pyrogram is a Telegram MTProto API Framework for Python
Which You can give it a phone number to create a user account as a bot:
see the doc
When you give it a phone number, telegram will send you a phone code to authentication and you can enter the phone code manually.
also you can give your script the phone code automatically by phone_code parameter in Client class:
see the client doc
I send my phone number from node.js script to python script and telegram send me a phone code to verify.
But when i send the phone code, it doesn't work correctly. actually it send the phone code again
What is my mistake?
my node.js code:
if(command == 'run cli'){
var spawn = require("child_process").spawn;
var process = spawn('python3', ["python/cli.py"]);
process.stdout.on('data', function(data) {
console.log(data.toString());
});
}
else if(command.substr(0, 9) == 'send code'){
var code = command.substr(10).trim();
var spawn = require("child_process").spawn;
var process = spawn('python3', ["python/cli_enter_code.py", code]);
process.stdout.on('data', function(data) {
console.log(data.toString());
});
}
cli.py file:
from pyrogram import Client
from pyrogram.raw import functions
api_id = someNumber
api_hash = "someHash"
with Client("my_account", api_id, api_hash, phone_number="my phone number") as app:
print('Bot is online...')
app.run()
cli_enter_code.py file:
import sys
code = sys.argv[1]
from pyrogram import Client
from pyrogram.raw import functions
api_id = someNumber
api_hash = "someHash"
with Client("my_account", api_id, api_hash, phone_number='my phone number', phone_code=code) as app:
print('Bot is online...')
app.run()

Related

Exchanging data between Python Telethon library and Node.js

I faced such a problem: in my small test app I have simple node.js (express) server and python script, which allows me to interact with Telegram API using Telethon library. In my scenario I have to provide my python script a phone number and a password. These data is asked in the input mode, so I can't figure out, how am I able to:
Accept input request from python script on node.js side;
Provide these credentials by node.js and pass them back via python's input;
Repeat this actions several times to gain all info I need.
These are my test files:
file.py
import os
from telethon import TelegramClient
api_id = 12345
api_hash = 'hash'
session = 'testing'
proxy = None
client = TelegramClient(session, api_id, api_hash, proxy=proxy).start()
def get_ids_list():
ids_dict = {}
async def do_fetch():
async for dialog in client.iter_dialogs():
ids_dict[dialog.name] = dialog.id
with client:
client.loop.run_until_complete(do_fetch())
return ids_dict
def print_ids_list():
async def do_print():
async for dialog in client.iter_dialogs():
print(dialog.name, 'has ID', dialog.id)
with client:
client.loop.run_until_complete(do_print())
print_ids_list()
When this script is run, I'm prompted the following input:
Please enter your phone (or bot token):
And this is my index.js, in which I want to pass prepared data to this input:
import express from "express";
import { spawn } from "child_process";
const app = express();
const port = 3000;
app.get("/", (req, res) => {
var myPythonScript = "path/to/file.py";
var pythonExecutable = "python";
var uint8arrayToString = function (data) {
return String.fromCharCode.apply(null, data);
};
const scriptExecution = spawn(pythonExecutable, [myPythonScript]);
scriptExecution.stdout.on("data", (data) => {
console.log(uint8arrayToString(data));
});
scriptExecution.stderr.on("data", (data) => {
console.log(uint8arrayToString(data));
});
scriptExecution.on("exit", (code) => {
console.log("Process quit with code : " + code);
});
});
app.listen(port, () =>
console.log(`Example app listening on port ${port}!`)
);
So, is there a way to solve this case?
Using with client is equivalent to client.start(), and as stated:
By default, this method will be interactive (asking for user input if needed), and will handle 2FA if enabled too.
You need to instead do what it does manually, remove with block, and make a function to authenticate (or confirm if already authorized).
for a minimal func example:
....
if not client.is_connected():
await client.connect()
if not await client.is_user_authorized():
await client.send_code_request(phone)
# get the code somehow, and in a reasonably fast way
try:
await client.sign_in(phone, code)
except telethon.errors.SessionPasswordNeededError:
'''
Retry with password.
note: it's necessary to make it error once
even if you know you have a pass, iow don't pass password the first time.
'''
await client.sign_in(phone, code, password=password)
return client
else:
return client
Dealing with the steps sequentially and interactivly while waiting for needed params to login successfully while also keeping in mind you have time limit until code expires is your task to handle any of their undefined behavior dependant on your usecase.

How do I authorize with a Telethon QR code?

I'm trying to authorize in telethon via QR.
In the docs of telegram I found the method exportLoginToken, which allows you to create a token for qr code.
If I understand it correctly, the desktop telegram client uses this mechanics. You scan the qr from an authorized device and the session opens on the pc.
Telethon also has it. Example from the documentation:
with TelegramClient(name, api_id, api_hash) as client:
result = client(functions.auth.ExportLoginTokenRequest(
api_id=42,
api_hash='some string here',
except_ids=[42]
))
print(result.stringify())
If we don't have an active session, it will create one when we enter as telethon.
For this we need a number and a code. Or an active session and a connected client
The telethon docs say:
Note that you must be connected before invoking this, as with any other request.
So in order to create an authorization token on the new device I must already be authorized?
How do I get a token for the qr code on a device that has no active sessions?
When the documentation says that you must be connected, it means that you must call the method TelegramClient.connect which connects you to telegram.
So if you do this, it will work out:
import telethon
from telethon import TelegramClient
from qrcode import QRCode
from base64 import urlsafe_b64encode as base64url
qr = QRCode()
def gen_qr(token:str):
qr.clear()
qr.add_data(token)
qr.print_ascii()
def display_url_as_qr(url):
print(url) # do whatever to show url as a qr to the user
gen_qr(url)
async def main(client: telethon.TelegramClient):
if(not client.is_connected()):
await client.connect()
client.connect()
qr_login = await client.qr_login()
print(client.is_connected())
r = False
while not r:
display_url_as_qr(qr_login.url)
# Important! You need to wait for the login to complete!
try:
r = await qr_login.wait(10)
except:
await qr_login.recreate()
TELEGRAM_API_ID=
TELEGRAM_API_HASH=
client = TelegramClient("SessionName", TELEGRAM_API_ID, TELEGRAM_API_HASH)
client.loop.run_until_complete(main(client))

How to work with slackbot in python?

I am trying to build a slackbot for my group , I tried sample codes and some other things but its not sending message to the group.
first i tried via terminal
export SLACK_API_TOKEN="my_token_id"
Then
from slackclient import SlackClient
import os
slack_token = os.environ["SLACK_API_TOKEN"]
sc = SlackClient(slack_token)
sc.api_call(
"chat.postMessage",
channel="#random",
text="Hello from Python! :tada:",
thread_ts="283.5127(dummy_id)",
reply_broadcast=False
)
print(sc)
#<slackclient.client.SlackClient object at 0x109b77ba8>
But there is no message in slack group.
I tried with this code:
from slackclient import SlackClient
import os
slack_token = os.environ['SLACK_API_TOKEN']
sc = SlackClient(slack_token)
print(sc.api_call("channels.list"))
its retuning :
{'error': 'invalid_auth', 'ok': False}
I am not getting what i am doing wrong , Access token is correct , i want to post some messages via a bot , so how i can create a bot on slack and using that bot i can send messages via python ?
I had similar issues when I implemented a slack bot with php & symfony.
It's not that simple to create and configure the slack app, bot and OAuth permissions properly.
I explained all these configurations in this blog post if you need it: https://blog.eleven-labs.com/en/en/replace-erp-by-slack-bot-with-dialogflow-and-symfony/
Also my code in PHP is very similar to what you need to parse Slack requests and post to its API.
Summary, TL;DR:
Go to https://api.slack.com/apps and click on 'Create New App'.
In this app configuration, go to the left menu 'Bot Users' or from 'Basic Information' > 'Add features and functionality' > 'Bots'.
Still in this app config, go to the menu 'OAuth & Permissions' and allow the scope 'chat:write:bot' and copy the value of 'OAuth Access Token'
From your code, call 'chat.postMessage' API method with an 'Authorization' header using previous token value.
built this from some examples found on the web: liza daly - brobot : github.com
and
How to Build Your First Slack Bot with Python : fullstackpython.com
certainly not the best implementation but it functions as an appropriate answer to (i think)
import random
import time
import re
from slackclient import SlackClient
bot_id = None
slack_token = 'xoxb-no.more.mister.nice.gui'
sc = SlackClient(slack_token)
# constants
RTM_READ_DELAY = 1 # 1 second delay between reading from RTM
DEFAULT_RESPONSE = "greetings: 'hello', 'hi', 'greetings', 'sup', 'what's up' / commands: 'do'"
DEFAULT_COMMAND = "do"
MENTION_REGEX = "^<#(|[WU].+?)>(.*)"
def parse_bot_commands(slack_events):
"""
parses a list of events coming from the slack rtm api to find bot commands
:param slack_events:
:return:
"""
for event in slack_events:
if event["type"] == "message" and not "subtype" in event:
user_id, message = parse_direct_mention(event["text"])
if user_id == bot_id:
return message, event["channel"]
return None, None
def parse_direct_mention(message_text):
"""
finds direct message and returns user id
:param message_text:
:return:
"""
matches = re.search(MENTION_REGEX, message_text)
# the first group contains the user name, the second group contains
# the remaining message
return (matches.group(1), matches.group(2).strip()) if matches else (None, None)
def handle_command(command, channel):
"""
executes bot command if the command is known
:param command:
:param channel:
:return:
"""
GREETING_KEYWORDS = ("hello", "hi", "greetings", "sup", "what's up",)
GREETING_RESPONSES = ["'sup brah", "hey", "*headnod*", "didjageddathingahsencha?"]
# default response is help text for the user
default_response = "Not sure what you mean. Try *{}*.".format(DEFAULT_RESPONSE)
# finds and executes the given command, filling the response
response = None
#implement more commands below this line
if command in GREETING_KEYWORDS:
response = random.choice(GREETING_RESPONSES)
else:
if command.startswith(DEFAULT_COMMAND):
response = "Sure...write some more code and I'll do that"
# Sends the response back to the channel
sc.api_call(
"chat.postMessage",
channel="#the_danger_room",
as_user="true:",
text=response or default_response)
if __name__ == "__main__":
if sc.rtm_connect(with_team_state=False):
print("Connected and running!")
#call web api method auth.test to get bot usre id
bot_id = sc.api_call("auth.test")["user_id"]
while True:
command, channel = parse_bot_commands(sc.rtm_read())
if command:
handle_command(command, channel)
time.sleep(RTM_READ_DELAY)
else:
print("Connection failed. Exception traceback printed above.")

How can I download the chat history of a group in Telegram?

I would like to download the chat history (all messages) that were posted in a public group on Telegram. How can I do this with python?
I've found this method in the API https://core.telegram.org/method/messages.getHistory which I think looks like what I'm trying to do. But how do I actually call it? It seems there's no python examples for the MTproto protocol they use.
I also looked at the Bot API, but it doesn't seem to have a method to download messages.
You can use Telethon. Telegram API is fairly complicated and with the telethon, you can start using telegram API in a very short time without any pre-knowledge about the API.
pip install telethon
Then register your app (taken from telethon):
the link is: https://my.telegram.org/
Then to obtain message history of a group (assuming you have the group id):
chat_id = YOUR_CHAT_ID
api_id=YOUR_API_ID
api_hash = 'YOUR_API_HASH'
from telethon import TelegramClient
from telethon.tl.types.input_peer_chat import InputPeerChat
client = TelegramClient('session_id', api_id=api_id, api_hash=api_hash)
client.connect()
chat = InputPeerChat(chat_id)
total_count, messages, senders = client.get_message_history(
chat, limit=10)
for msg in reversed(messages):
# Format the message content
if getattr(msg, 'media', None):
content = '<{}> {}'.format( # The media may or may not have a caption
msg.media.__class__.__name__,
getattr(msg.media, 'caption', ''))
elif hasattr(msg, 'message'):
content = msg.message
elif hasattr(msg, 'action'):
content = str(msg.action)
else:
# Unknown message, simply print its class name
content = msg.__class__.__name__
text = '[{}:{}] (ID={}) {}: {} type: {}'.format(
msg.date.hour, msg.date.minute, msg.id, "no name",
content)
print (text)
The example is taken and simplified from telethon example.
With an update (August 2018) now Telegram Desktop application supports saving chat history very conveniently.
You can store it as json or html formatted.
To use this feature, make sure you have the latest version of Telegram Desktop installed on your computer, then click Settings > Export Telegram data.
https://telegram.org/blog/export-and-more
The currently accepted answer is for very old versions of Telethon. With Telethon 1.0, the code can and should be simplified to the following:
# chat can be:
# * int id (-12345)
# * str username (#chat)
# * str phone number (+12 3456)
# * Peer (types.PeerChat(12345))
# * InputPeer (types.InputPeerChat(12345))
# * Chat object (types.Chat)
# * ...and many more types
chat = ...
api_id = ...
api_hash = ...
from telethon.sync import TelegramClient
client = TelegramClient('session_id', api_id, api_hash)
with client:
# 10 is the limit on how many messages to fetch. Remove or change for more.
for msg in client.iter_messages(chat, 10):
print(msg.sender.first_name, ':', msg.text)
Applying any formatting is still possible but hasattr is no longer needed. if msg.media for example would be enough to check if the message has media.
A note, if you're using Jupyter, you need to use async directly:
from telethon import TelegramClient
client = TelegramClient('session_id', api_id, api_hash)
# Note `async with` and `async for`
async with client:
async for msg in client.iter_messages(chat, 10):
print(msg.sender.first_name, ':', msg.text)
Now, you can use TDesktop to export chats.
Here is the blog post about Aug 2018 update.
Original Answer:
Telegram MTProto is hard to use to newbies, so I recommend telegram-cli.
You can use third-party tg-export script, but still not easy to newbies too.
You can use the Telethon library. for this you need to register your app and connect your client code to it (look at this).
Then to obtain message history of a entry (such as channel, group or chat):
from telethon.sync import TelegramClient
from telethon.errors import SessionPasswordNeededError
client = TelegramClient(username, api_id, api_hash, proxy=("socks5", proxy_ip, proxy_port)) # if in your country telegram is banned, you can use the proxy, otherwise remove it.
client.start()
# for login
if not client.is_user_authorized():
client.send_code_request(phone)
try:
client.sign_in(phone, input('Enter the code: '))
except SessionPasswordNeededError:
client.sign_in(password=input('Password: '))
async for message in client.iter_messages(chat_id, wait_time=0):
messages.append(Message(message))
# write your code

Python - how to send a message through Parse.com to a specific device ID using ParsePy?

I have a simple web service application that I'm using to test sending pushes through Parse.com from Python.
My app uses Flask module and ParsePy module. The code listed below works for the Push.alert(notification, channels=["pushDebug"]) - I see a notification on the device subscribed to that channel.
Now I'm trying to send a push to a specific device ID, but am not seeing the notification go through.
What is the correct syntax to define a "Where" query for a specific user ID (a custom field defined in Parse)? Here's the line of code that needs this query: Push.alert(notification, where={"kDeviceID": str(deviceID)})
Examples I found
Push.alert({"alert": "The Mets scored! The game is now tied 1-1.",
"badge": "Increment", "title": "Mets Score"}, channels=["Mets"],
where={"scores": True})
OR (taken from parse official documentation)
"where": {
"user_id": "user_123"
}
My webservice:
from flask import Flask
from flask import Response, jsonify, request, redirect, url_for
from parse_rest.connection import register
from parse_rest.installation import Push
import socket
app = Flask(__name__)
didRegisterWithParse = 0
def checkRegister():
if didRegisterWithParse == 0:
register(
"APPLICATION_ID",
"REST_API_KEY",
master_key="MASTER_KEY"
)
global didRegisterWithParse
didRegisterWithParse = 1
return
#app.route('/testparsepush/')
def testparsepush():
deviceID = request.args.get('device_id')
hostString = "http://%s:5000/getcommand/" % socket.gethostbyname(socket.gethostname())
notification = {"alert": "Parse Test","title": "Push from Python", "host": hostString}
checkRegister()
# send push notification through parse
resp = None
if deviceID:
Push.alert(notification, where={"kDeviceID": str(deviceID)})
#prepare response
resp = jsonify(message = 'sent alert to deviceID: ' + str(deviceID))
else:
Push.alert(notification, channels=["pushDebug"])
resp = jsonify(message = 'sent alert to channel pushDebug')
resp.status_code = 200
return resp
if __name__ == '__main__':
print(socket.gethostbyname(socket.gethostname()))
app.run(host='0.0.0.0')

Categories