400 (Bad Request) error when using Pushbullet Ephemerals - python

I'm working on a simple command-line Pushbullet Python project, and have the following code:
from settings import *
import urllib
import urllib2
def pushSms(number, message):
url = 'https://api.pushbullet.com/v2/ephemerals'
values = {
"type": "push",
"push": {
"type": "messaging_extension_reply",
"package_name": "com.pushbullet.android",
"source_user_iden": settings["PUSHBULLET_USER_IDEN"],
"target_device_iden": settings["PUSHBULLET_SMS_IDEN"],
"conversation_iden": number,
"message": message
}
}
headers = {"Authorization" : "Bearer " + settings["PUSHBULLET_API_KEY"]}
data = urllib.urlencode(values)
req = urllib2.Request(url, data, headers)
response = urllib2.urlopen(req)
return response
Example usage might be pushSms("555 555 5555", "Hi there!").
This takes advantage of the Pushbullet android app access to SMS, as documented here. I've checked my settings variables and they're all valid (in fact, they're currently in use in a JavaScript version of nearly this exact code in another project of mine.
My suspicion is that this is a basic Python syntax/urllib2 misuse or error, but I've been staring/Googling for hours and can't see my error. Thoughts?

I can't tell for certain (the response from the server may contain more information), but because we accept both form encoded and json requests, you probably need to set the header "Content-Type: application/json" on the request.
If that's not the case, could you post the body of the 400 response?

Related

Force check with NagiosXI API using Python scripts

While trying to configure a script using python to write comments using the API i'm encounteringthe following error mesage:
{"error":"Unknown API endpoint."}
The code given by NagiosXI API System Reference, system/corecommand is the following:
curl -XPOST "http://192.168.1.239/nagiosxi/api/v1/system/corecommand?apikey=<API_Key>" -d "cmd=ADD_HOST_COMMENT;localhost;1;%user%;This is a test comment"
This translated to python should be something like this:
import requests
url = "http://192.168.1.239/nagiosxi/api/v1/system/corecommand"
api_key = "<API_Key>"
params = {
"cmd": "ADD_HOST_COMMENT",
"host_name": "localhost",
"entry_time": 1,
"author": "%user%",
"comment_data": "This is a test comment",
"apikey": api_key
}
response = requests.post(url, params=params)
if response.status_code == 200:
print("Comment added successfully")
else:
print("Error adding comment: ", response.text)
At the moment i'm getting a 200 response but with the error message previously mentioned: "{"error":"Unknown API endpoint."}"
Currently using NagiosXI version 5.9.3
Both systems are on the same network an "GET" request go through without any hiccups.
Many thanks in advance;

Python: requests lib post request not sending proper json format data

I am trying to connect to a very closed source database system via REST API to pull some data. The API so weird that it just gives you status code 400 & nothing much. No information or error pointing to what is wrong with the provided data. I am calling this API using postman & it is giving me proper response but when I use Python's requests lib to call this API I am getting 400 status (Which means there is something wrong with the provided data with the request).
This is my code.
def pull_data():
url = construct_url(configs.get("get_data_path"))
payload = json.dumps([
{
"SampleInterval": 600000,
"GetEnum": False,
"ResampleMethod": "Around",
"MinimumConfidence": 0,
"MaxRows": 100,
"TimeFormat": 6,
"ReductionData": "avg",
"TagName": [
"NC_AI3",
"NC_AI32"
],
"StartTime": "05/16/2022 08:49:26.000",
"EndTime": "05/16/2022 13:03:36.000",
"OutputTimeFormat": 6,
"EventSequence": 0
}
])
headers = {'Content-Type': 'application/json'}
res = requests.post(url, json=payload, verify=False, auth=HTTPBasicAuth(configs.get("user"), configs.get("password")), headers=headers)
print("----------", "Status Code", res.status_code, "-------")
I think somehow the json data sent via the request.post method is not getting recognised by the API. I think it is something to do with the fact that I am sending list of dict as json error not a usual dict as we do or see everywhere.
Can please someone tell if I am sending the json data correctly or not or is there any other way to do it?

changing ampersands to %26

I am using Python-requests to pull data from a website. I am doing this currently :
params = {'A':'something', 'B':'something'}
response = requests.get(url, params = params)
which gives me: https://someurl?query=&A=something&B=something
This is all perfectly fine and great.
However, the website doesn't accept my API call. After some meddling around, I discovered that my target url is actually this:
https://someurl?query=%26A=something%26B=something
Hence my question : Is there a workaround for this problem? I have combed through requests' documentation and found nothing. I really don't feel like working with the url directly because I really like Python-requests.
The URL https://someurl?query=&A=something&B=something is very different than the URL https://someurl?query=%26A=something%26B=something.
URL1 https://someurl?query=&A=something&B=something is interpreted by the HTTP server as a request with 3 parameters: {
"query": "",
"A": "something",
"B": "something"
}
URL2 https://someurl?query=%26A=something%26B=something is interpreted by the HTTP server as a request with 1 parameter: {
"query": "&A=something%26B=something"
}
where "%26" is decoded as "&" character so value is decoded as &A=something&B=something.
A HTTP query with a single parameter "query" with value of &A=something&B=something needs to be properly encoded otherwise it will be converted into the wrong value. If using params options in requests API then the encoding is automatically done for you.
url = "http://localhost:8000"
params = {'query': '&A=something&B=something'}
response = requests.get(url, params=params)
print(response.status_code)
If you want to debug requests under the covers then add this before calling requests.get().
import requests
import logging
# You must initialize logging, otherwise you'll not see debug output.
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
url = "http://localhost:8000"
params = {'query': '&A=something&B=something'}
response = requests.get(url, params=params)
Output:
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): localhost:8000
DEBUG:urllib3.connectionpool:http://localhost:8000 "GET /?query=%26A%3Dsomething%26B%3Dsomething HTTP/1.1" 200 5
Notice the "=" in the URL is also enocded to avoid any confusion since "&" and "=" are special characters in URL string.
Try using urllib.parse.unquote() before sending requests to the server :
from urllib.parse import unquote
url="https://someurl?query=%26A=something%26B=something"
print(unquote(url))
# https://someurl?query=&A=something&B=something
And now you can send requests normally.

Python PUT call fails while curl call doesn't

Best wishes (first things first!)
I want to enable/disable a PoE port on my UniFi switch. For this I aim using Python 3.9.1 (first time) with the following code:
import requests
import json
import sys
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
gateway = {"ip": "MYSERVER.COM", "port": "8443"}
headers = {"Accept": "application/json", "Content-Type": "application/json"}
login_url = f"https://{gateway['ip']}:{gateway['port']}/api/login"
login_data = {
"username": "MYUSERNAME",
"password": "MYPASSWORD"
}
session = requests.Session()
login_response = session.post(login_url, headers=headers, data=json.dumps(login_data), verify=False)
if (login_response.status_code == 200):
api_url_portoverrides = 'api/s/default/rest/device/MYDEVICEID'
poe_url = f"https://{gateway['ip']}:{gateway['port']}/{api_url_portoverrides}"
# build json for port overrides
json_poe_state_on = '{"port_overrides": [{"port_idx": 6, "portconf_id": "MYPROFILE1"}]}'
json_poe_state_off = '{"port_overrides": [{"port_idx": 6, "portconf_id": "MYPROFILE2"}]}'
post_response = session.put(poe_url, headers=headers, data=json.dumps(json_poe_state_off))
print('Response HTTP Request {request}'.format(request=post_response.request ))
else:
print("Login failed")
The login works (I get the 2 security cookies and tried them in Paw (a macOS REST API client) to see if these were ok)) but the second call, the. PUT, returns OK but noting happens.
Before I've done this in Python, I tried all my calls in Paw first and there it works. I tried everything in bash with curl and there it works too. So I am a bit at a loss here.
Anyone has an idea?
Thank you for your time!
Best regards!
Peter
Solved it! By looking into what was posted with Wireshark I saw that the payload was different. The culprit was the json.dumps function which encoded the string by putting a backslash in front of each double quote.
It works now!

Node Express Empty body when using python API POST (requests library)

I'm using the starter kit by #ErikRas
With the following code, I'm having trouble authenticating my python program.
Here's my python:
import requests
URL="http://localhost"
PORT="3030"
Session = requests.Session()
Request = Session.post(URL+':'+PORT+'/login', data={'name':'AuthedUserName'})
# (Password to follow proof of concept obviously)
In my api.js file i just had:
import express from 'express';
import session from 'express-session';
import bodyParser from 'body-parser';
import config from '../src/config';
import * as actions from './actions/index';
import {mapUrl} from 'utils/url.js';
import http from 'http';
const app = express();
const server = new http.Server(app);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(session({
secret: 'react and redux rule!!!!',
resave: false,
saveUninitialized: false,
cookie: { maxAge: 60000 }
}));
app.use((req, res) => {
/* There's heaps here, but all that is relevant is: */
console.log(req.body)
In the console i'm just getting {}
I found this article:
req.body empty on posts
and
Python Post Request Body appears empty in Node server when sent
but as you can see i'm already using bodyparser.json and bodyparser.urlencoded.extended = true
Okay, so i compared my pythons request against my web-app's request by printing the request to the console in node.
I found that the web app had more in its header than the python's requests' request. WebApp:
referer: 'http://localhost:3001/login'
origin: 'http://localhost:3001'
host: 'http://localhost:3001'
connection: 'close'
So I included this in my header, it worked!
I wanted to see which header property was 'necessary', so i gradually pulled everything out to see if this broke the POST request.
Turns out i managed to pull everything out! So what i'm using now is this:
r = Session.post(URL+':'+PORT+'/login',headers = {}, data={'name':'AuthedUserName'})
That's it!! I'd like to understand why headers={} works, but i need to moving forward with my project!!
<<<<<<---- Edit ---->>>>>>
Above is 'half' right, since my web app is using json and i want to use json, what i needed to do was change my header to
headers = {u'content-type': u'application/json'}
Then use json.dumps on the payload only!
r = session.post('http://'+DB_URL+':3030/sinumecUpdate', headers = headers, data = json.dumps(dataObject))
I also needed to pull out
app.use(bodyParser.urlencoded({ extended: true }));
From my node API and stick with only the JSON body parser.
import requests
import json
url = 'http://127.0.0.1'
data={'name':'AuthedUserName'}
headers = {'content-type': 'application/json'}
r = requests.post(url=url, data=json.dumps(data), headers=headers)

Categories

Resources