Google App Script - Telegram Bot - setChatPhoto - google-apps-script

i want a telegram bot that set a specific photo as a group image. Here you can see the bot api about that method(https://core.telegram.org/bots/api#setchatphoto).
I'm using this function but it doesn't work.
function myFunction(){
var chatId = SUPERGOUP_CHAT_ID
var photo = {
file_id: FILE_ID,
file_size: 425707,
file_path: 'documents/file_2.png'
}
var data = {
method: "post",
payload: {
method: "setChatPhoto",
chat_id: String(zone),
photo: JSON.stringify(photo)
}
}
UrlFetchApp.fetch('https://api.telegram.org/bot' + token + '/', data);
}
Telegram answer to the function up here:
{"ok":false,"error_code":400,"description":"Bad Request: photo should be uploaded as an InputFile"}
Searching online i found this solution but it also doesn't work.
function uploadFile() {
var group = SUPERGOUP_CHAT_ID
var boundary = "labnol";
var blob = DriveApp.getFileById('FILE_ID').getBlob();
var attributes = "{\"name\":\"asd.jpg\", \"parent\":{\"id\":\"FOLDER_ID\"}}";
var requestBody = Utilities.newBlob(
"--"+boundary+"\r\n"
+ "Content-Disposition: form-data; name=\"attributes\"\r\n\r\n"
+ attributes+"\r\n"+"--"+boundary+"\r\n"
+ "Content-Disposition: form-data; name=\"file\"; filename=\""+blob.getName()+"\"\r\n"
+ "Content-Type: " + blob.getContentType()+"\r\n\r\n").getBytes()
.concat(blob.getBytes())
.concat(Utilities.newBlob("\r\n--"+boundary+"--\r\n").getBytes());
var options = {
method: "post",
contentType: "multipart/form-data; boundary="+boundary,
payload: {
method: "setChatPhoto",
chat_id: String(group),
photo: requestBody
}
};
var request = UrlFetchApp.fetch('https://api.telegram.org/bot' + token , options);
Logger.log(request.getContentText());
}
Telegram answer to the function up here:
Timeout: https://api.telegram.org/bot_TOKEN
Can you maybe find a solution?
Thanks in advance.

Related

FinBox.com logging in with UrlFetchApp to access another link?

I can't log in successfully from Google Apps Script despite looking for solutions hours long, including many entries in SoF.
The login process sends a POST request to this url: https://finbox.com/_/api/v5/tokens
Input of the credentials happens here: https://finbox.com/login/email
Response code is 400.
Any help will be really appreciated :)
So far I ended up with this:
function testFinBoxWithCredentials(stock = "AAPL") {
var options = {
method: 'post',
contentType: 'application/json',
payload: {
email: 'xxxxxxxxx',
password: 'xxxxxxxxx'
},
muteHttpExceptions: true,
followRedirects: false
};
const response = UrlFetchApp.fetch("https://finbox.com/_/api/v5/tokens", options);
Logger.log(response.getResponseCode());
if ( response.getResponseCode() == 200 ) {
Logger.log("Couldn't login.");
}
else if ( response.getResponseCode() == 302 ) {
Logger.log("Logged in successfully");
var cookie = response.getAllHeaders()['Set-Cookie'];
Logger.log(cookie);
//Access then a link like https://finbox.com/NASDAQGS:AAPL
/* var cookies = response.getAllHeaders()['Set-Cookie'];
for (var i = 0; i < cookies.length; i++) {
cookies[i] = cookies[i].split( ';' )[0];
};
url2 = "https://finbox.com/NASDAQGS:AAPL";
options2 = {
"method": "get",
"headers": {
"Cookie": cookies.join(';')
}
}
var response2 = UrlFetchApp.fetch(url2, options2);
var content = response2.getContentText();
Logger.log(content)*/
} ```

Parsing JSON Bing Search API using JQuery

I am trying to parse Bing Search API Version 7 JSON using the following code, but not sure what I am doing wrong. Would like to parse "name" and "url", my code is below.
Bing JSON Results are at the following URL -> http://52.15.219.114/bing2.php?q=freebsd&s=10&p=0&m=en-us
var e = escape($('#book').val());
var pg = 10;
var limit = 0;
$.ajax({
url: uri,
method: "GET",
data: { q:e, s:pg, p:limit },
success: function(data) {
len = data.webPages.value.length
for (i=0; i<len; i++ ){
results += "<p><a href='" + data.webPages.value[i].url + "'>" + data.webPages.value[i].name + "</a>: " + data.webPages.value[i].snippet + "</p>";
}
$("#bookout").html(results);
},
error: function() {
// console.log(data);
}
});
Below is a fix for parsing the Bing Search JSON API.
var e = escape($('#book').val());
var pg = 10;
var limit = 0;
$.ajax({
url: uri,
method: "GET",
data: { q:e, s:pg, p:limit },
success: function(data) {
var obj = JSON.parse(data)
var ocean = obj.webPages.value; //client prop is an array
for(var i = 0; i < ocean.length; i++){
//alert(ocean[i].name);
//FORMAT RESULTS
var ocean_format = '<div><div>' + '' + ocean[i].name + '</div><div>' + ocean[i].snippet + '</div><div class="text-secondary">' + ocean[i].displayUrl + '</div></div>';
$("#bookout").append(ocean_format);
}//END SEARCH RESULTS
},
error: function() {
// console.log(data);
}
});

Google App Script fetch request with Digest auth issue

I am trying to retrieve some info from the camera system DVR from HIK Vision with GAS' UrlFetchApp. I am able to perform a successful request with Postman but having trouble getting this to work with the Google App Script's UrlFetchApp.fetch. I confirmed that my Digest calculation is correct. I did that by substituting values for nonce, cnonce, qop etc in my GAS with the ones which were in Postman and got the same Response string as the Postman did. See images of the Postman below:
Postman gets a 200 response and all the data that I need.
The way my app works is it sends a first request and gets 401 response. Then it sends a second request with the auth header calculated from the data received from the first request. I always get 401 no matter what I do. I played with the double quotes in the headers properties etc.
Here's the code:
function getRecordedDaysCount(){
const url = 'my_server_url';
const userName = 'user';
const pass = "password";
const uri = "/ISAPI/ContentMgmt/record/tracks/101/dailyDistribution";
const method = "POST"
const updatedUrl = url + uri;
let year = '2021';
let month = '03';
//payload required by the server for this request
let payload = '<?xml version: "1.0" encoding="utf-8"?><trackDailyParam><year>' + year + '</year><monthOfYear>' + month + '</monthOfYear></trackDailyParam>';
let options = {
"method" : method,
"muteHttpExceptions": true,
"headers":{
"Accept": "application/xml, text/plain, */*",
}
}
let data = UrlFetchApp.fetch(updatedUrl, options);
if(data.getResponseCode() == 401){
let wwwAuthenticate = data.getAllHeaders()["WWW-Authenticate"];
// Example WWWAuthenticate
// "Digest realm="493b21e13dddb4ef7745edaa", domain="::", qop="auth",
// nonce="17fbf10682dc4a7ceb04206cbcd95d8d:1616709300571", opaque="", algorithm="MD5", stale="FALSE""
let authData = wwwAuthenticate.split(',');
let authType = authData[0].split(' ')[0]; // Digest
if(authType === "Digest"){
let realm = authData[0].split('"')[1]; // "493b21e13dddb4ef7745edaa"
let qop=authData[2].split('"')[1]; // "auth"
let nonce = authData[3].split('"')[1]; // "17fbf10682dc4a7ceb04206cbcd95d8d:1616709300571"
let algorithm = authData[5].split('"')[1]; // "MD5"
let nc="00000001";
let cnonce= new Date().getTime().toString(16);
let hash1 = signMD5(userName +':'+ realm +':'+ pass);
let hash2 = signMD5(method+':'+ uri);
let response = signMD5(hash1+':'+nonce+':'+nc+':'+cnonce+':'+qop+':'+hash2);
let digestAuth = "Digest username=\"" + userName + "\"" +
", realm=\"" + realm + "\"" +
", nonce=\"" + nonce + "\"" +
", uri=\"" + uri + "\"" +
", qop=auth" +
", nc=" + nc +
", algorithm=\"MD5\"" +
", cnonce=\"" + cnonce + "\"" +
", response=\"" + response + "\"";
let headers = {
"Content-Type": "text/plain", // copied from Postman
"Accept-Encoding": "gzip, deflate, br", // copied from Postman
"Authorization": digestAuth,
}
let options = {
"method" : method,
"muteHttpExceptions": true,
"headers": headers,
"payload": (payload)
}
logUrlFetch(updatedUrl, options);
}
}
}
function signMD5(message){
let signature = Utilities.computeDigest(
Utilities.DigestAlgorithm.MD5,
message,
Utilities.Charset.UTF_8);
let signatureStr = '';
for (i = 0; i < signature.length; i++) {
let byte = signature[i];
if (byte < 0)
byte += 256;
let byteStr = byte.toString(16);
// Ensure we have 2 chars in our byte, pad with 0
if (byteStr.length == 1) byteStr = '0'+byteStr;
signatureStr += byteStr;
}
Logger.log(signatureStr);
return signatureStr;
}
function logUrlFetch(url, opt_params) {
let params = opt_params || {};
params.muteHttpExceptions = true;
let request = UrlFetchApp.getRequest(url, params);
Logger.log('Request: >>> ' + JSON.stringify(request));
let response = UrlFetchApp.fetch(url, params);
Logger.log('Response Code: <<< ' + response.getResponseCode());
Logger.log('Response text: <<< ' + response.getContentText());
if (response.getResponseCode() >= 400) {
throw Error('Error in response: ' + response);
}
return response;
}
These are the logs I'm getting:
headers after the first request
log after the second request
I compared the headers in the Postman and my app multiple times and they are mostly the same with some differences. The UrlFetchApp.fetch adds a few headers to the request however I added them also in Postman and it still worked so I concluded these additional headers were not a problem. Also the UrlFetchApp.fetch sends a request method as 'post' (lower case) and the Postman uses all caps - 'POST'. The http method is a part of the Digest HA2 calculation, which is case sensitive. This was the only idea that I had for why my requests didn't work. I changed my app's method to lower case 'post' for the digest calculation and for the headers and this did not help.
Is there a way to send requests in the Google App Script other than UrlFetchApp.fetch?
Thanks a lot!

Telegram BOT API, method setMyCommands, Google Apps Script

I want to set some command on my t-bot, but i cant understand how to do that
var token = "123456....";
var url = "https://api.telegram.org/bot" + token;
function setMyCommands(chat_id, message_id){
var data = {
method: "post",
payload:{
method: "setMyCommands",
chat_id: String(chat_id),
message_id: message_id,
parse_mode: "HTML"
}
};
UrlFetchApp.fetch(url + '/', data);
}
Now, I am doing like
if message is "/command" to do so. through following:
function sendMessage(id, text, keyBoard){
var data = {
method: "post",
payload: {
method: "sendMessage",
chat_id: String(id),
text: text,
parse_mode: "HTML",
reply_markup: JSON.stringify(keyBoard)
}
};
UrlFetchApp.fetch(url + "/", data);
}
function doPost(e) {
var contents = JSON.parse(e.postData.contents);
var id = contents.message.from.id;
var text = contents.message.text;
if (text == "/command") {
sendMessage(id,"someTEXT...")
}
}
could u pls, also explain what should var data look like and where can I take a form(or structure) of this to apply other methods from telegram bot API
Pyhton case:
create variables:
BOT_TOKEN = '12324'
BOT_COMMANDS= [{"command":"a", "description":"aaa"},{"command":"b","description":"bbb"}]
create the function:
def setMyCommands():
send_text = 'https://api.telegram.org/bot' + BOT_TOKEN + '/setMyCommands?commands=' + str(json.dumps(BOT_COMMANDS) )
response = requests.get(send_text)
and finnaly execute:
if __name__ == '__main__':
#getMyCommands()
setMyCommands()

Google Service Account Delegation 404 error

I am attempting to authenticate with a service account to work on behalf of a user account on the domain. I have delegated admin access and added to the GSuite console. I can get an access token with the below but the making batch requests to copy drive files returns "code: 404, message: 'File not found:". The below code is writted in Google Apps Script. Am I missing something form the process to creating and authenticating the service account?
var CREDENTIALS = {
private_key: "-----BEGIN PRIVATE KEY----- XXXXXXX \n-----END PRIVATE KEY-----\n",
client_email: "XXXXXX#fXXXXXX.iam.gserviceaccount.com",
client_id: "1XXXXXXXXXXXXXXXX",
user_email: "XXXXX#XXXX.XXX.XXX",
scopes: ["https://www.googleapis.com/auth/drive","https://www.googleapis.com/auth/spreadsheets","https://www.googleapis.com/auth/userinfo.email","https://www.googleapis.com/auth/script.external_request"]
};
function oAuthToken(){
var url = "https://www.googleapis.com/oauth2/v3/token";
var header = {
alg: "RS256",
typ: "JWT",
};
var now = Math.floor(Date.now() / 1000);
var claim = {
iss: CREDENTIALS.client_id,
sub: CREDENTIALS.user_email,
scope: CREDENTIALS.scopes.join(" "),
aud: url,
exp: (now + 3600).toString(),
iat: now.toString(),
};
var signature = Utilities.base64Encode(JSON.stringify(header)) + "." + Utilities.base64Encode(JSON.stringify(claim));
var jwt = signature + "." + Utilities.base64Encode(Utilities.computeRsaSha256Signature(signature, CREDENTIALS.private_key));
var params = {
method: "post",
payload: {
assertion: jwt,
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
},
};
var res = UrlFetchApp.fetch(url, params).getContentText();
return JSON.parse(res)
}
The batch process is a bit rough but this is the gist of it.
var request={
batchPath:
requests:[]
}
var backoff =0
function batch(request) {
var oAuth=oAuthToken().access_token
var url ='https://www.googleapis.com/'+request.batchPath
var body =request.requests
if(body.length<1){
return []
}
var boundary = 'xxxxxxxxxx';
var contentId = 0;
var data = '--' + boundary + '\r\n';
for (var i in body) {
if(typeof body[i]=='object'){
data += 'Content-Type: application/http\r\n';
data += 'Content-ID: ' + ++contentId + '\r\n\r\n';
data += body[i].method + ' ' + body[i].endpoint + '\r\n';
data += body[i].requestBody ? 'Content-Type: application/json; charset=utf-8\r\n\r\n' : '\r\n';
data += body[i].requestBody ? JSON.stringify(body[i].requestBody) + '\r\n' : '';
data += "--" + boundary + '\r\n';
}
}
var parseBatchRes = function(res) {
var splittedRes = res.split('--batch');
return splittedRes.slice(1, splittedRes.length - 1).map(function(e) {
return {
contentId: Number(e.match(/Content-ID: response-(\d+)/)[1]),
status: Number(e.match(/HTTP\/\d+.\d+ (\d+)/)[1]),
object: JSON.parse(e.match(/{[\S\s]+}/)[0]),
};
});
};
var payload = Utilities.newBlob(data).getBytes();
var head = {Authorization: 'Bearer ' + oAuth}
var options = {
method: 'POST',
contentType: 'multipart/mixed; boundary=' + boundary,
payload: payload,
headers: head,
muteHttpExceptions: false
};
var complete=false;
var finalResponse=[];
for (var n=0; n<=backoff; n++) {
if(complete){
break;
}
var complete = true
console.log('backoff',n);
var response =UrlFetchApp.fetch(url, options).getContentText();
for(var j=0;j<response.length;j++){
if(response[r].status!=200){
var complete = false
}
}
}
}
Add the supportsAllDrives = true query parameter to the request.
The parameters indicates whether the requesting application supports both My Drives and shared drives and the default value for this is false.
Reference
Drive API Parameters