I am using redis with Lua to fetch sessiondata of any admin from Django project .In Django project sessiondata is encoded into base64 form.
sessiondata value is :
session_data = "NzlmZjZmNWQxMGIzNTQzMDZhNDZjNzJiZGQ4OWZiY2NjNDg0NDVlZTqAAn1xAShVEl9hdXRoX3VzZXJfYmFja2VuZHECVSlkamFuZ28uY29udHJpYi5hdXRoLmJhY2tlbmRzLk1vZGVsQmFja2VuZHEDVQ1fYXV0aF91c2VyX2lkcQSKAgEKdS4="
My Lua code to decode session data is
-- decode base64 code fetch from django session data
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
local function dec(data)
data = string.gsub(data, '[^'..b..'=]', '')
return (data:gsub('.', function(x)
if (x == '=') then return '' end
local r,f='',(b:find(x)-1)
for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
return r;
end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
if (#x ~= 8) then return '' end
local c=0
for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
return string.char(c)
end))
end
when I am running print(dec(session_data)) I am getting
output = 79ff6f5d10b354306a46c72bdd89fbccc48445ee:�}q(U_auth_user_backendqU)django.contrib.auth.backends.ModelBackendqU _auth_user_idq� u.
while output suppose to be
{'_auth_user_id': 2561L, '_auth_user_backend': 'django.contrib.auth.backends.ModelBackend'}
like Django we had.
Please let me know what I am doing wrong .
A quick google search yields this blog post.
This is the (abridged, nonverifying) python code he has to do the decoding of sessiondata:
def decode(session_data, secret_key, class_name='SessionStore'):
encoded_data = base64.b64decode(session_data)
utoken, pickled = encoded_data.split(b':', 1)
return pickle.loads(pickled)
In other words, your expectations are wrong. The un-base64-ed data contains a checksum hash (79ff6...445ee) followed by a : followed by serialized (via pickle) python data (�}q(U_auth..._user_idq� u.).
If you really want to understand how to decode python picked data, see PEP 307.
If you are using django 1.5.3+ you can use json serializer so that you don't have to try to decode python pickles in lua ;) Json serializer is default in django 1.6+.
Related
I am working on a python program that turns on/off my mining rig with Nicehash API. I did everything that I need to but I am stuck with what to put in query string.
In header of post request must be X-auth which which is built from API Key and HMAC signature. On NiceHash website it says that HMAC signature must be build like this:
Input structure is the following:
-API Key
-X-Time request header value
-X-Nonce request header value
-Empty field
-X-Organization-Id request header value
-Empty field
-Request method (example: GET, POST, DELETE, PUT)
-Request path (example: /main/api/v2/hashpower/orderBook)
-Request query string (example: algorithm=X16R&page=0&size=100, The query string should be the same as
passed to the server - without the leading question mark)
Input is a byte array composed of ordered fields using zero byte (0x00) as a separator. There is no
separator before the first field or after the last field. Some fields are always empty in which case the
separators immediately follow one another. For request body you should use the raw bytes as they are sent
to the server. For JSON messages the character encoding should always be UTF-8.
So input should look like this (already hashed in UTF-8) and then be hashed again (in order from first to last:
API KEY,TIME,NONCE,ORGANISATION ID,REQUEST METHOD,REQUEST PATH,REQUEST QUERY STRING) :
4ebd366d-76f4-4400-a3b6-e51515d054d6 ⊠ 1543597115712 ⊠ 9675d0f8-1325-484b-9594-c9d6d3268890 ⊠ ⊠ da41b3bc-3d0b-4226-b7ea-aee73f94a518 ⊠ ⊠ GET ⊠ /main/api/v2/hashpower/orderBook ⊠ algorithm=X16R&page=0&size=100
(this sign: ⊠ is zero byte: 0x00)
My code:
import hashlib
import uuid
import requests
import json
import hmac
url = "https://api2.nicehash.com/main/api/v2/mining/rigs/status2"
path = "/main/api/v2/mining/rigs/status2"
ms = str(json.loads(requests.get('https://api2.nicehash.com/api/v2/time').text)['serverTime'])
req_id = str(uuid.uuid4())
nonce = str(uuid.uuid4())
org_id = organizationId
sec_key = secretKey
apiKey = apiKey
method = "POST"
query = ?
input = bytearray(f"{apiKey}\00{ms}\00{nonce}\00\00{org_id}\00\00{method}\00{path}\00{query}", "utf-8")
secret=hmac.new(bytearray(sec_key, "utf-8"), input, hashlib.sha256).hexdigest()
auth = apiKey + ":" + secret
#HEADER
header = {
"X-Time":ms,
"X-Nonce":nonce,
"X-Organization-Id":org_id,
"X-Auth":auth,
"X-Request-Id":req_id}
#BODY
body = {
"rigId": "SOMETHING",
"action": "STOP"
}
r=requests.post(url=url, headers=header, params=body)
print(r)
print(r.json())
But on website the example demostrates if you want to get a hashpower order book and I understand query string there. But I dont know what to put in query string in my case.
For now this is the main problem for me so the rest of the code is not finished yet.
try this:
query="action=STOP&rigId=yourigid" #stops certain rig
I tried to use https://www.nicehash.com/docs/rest and https://www.nicehash.com/docs/
picture of what worked for me
I am working with webhooks from Bold Commerce, which are validated using a hash of the timestamp and the body of the webhook, with a secret key as the signing key. The headers from the webhook looks like this :
X-Bold-Signature: 06cc9aab9fd856bdc326f21d54a23e62441adb5966182e784db47ab4f2568231
timestamp: 1556410547
Content-Type: application/json
charset: utf-8
According to their documentation, the hash is built like so (in PHP):
$now = time(); // current unix timestamp
$json = json_encode($payload, JSON_FORCE_OBJECT);
$signature = hash_hmac('sha256', $now.'.'.$json, $signingKey);
I am trying to recreate the same hash using python, and I am always getting the wrong value for the hash. I've tried several combinations, with and without base64 encoding. In python3, a bytes object is expected for the hmac, so I need to encode everything before I can compare it. At this point my code looks like so :
json_loaded = json.loads(request.body)
json_dumped = json.dumps(json_loaded)
# if I dont load and then dump the json, the message has escaped \n characters in it
message = timestamp + '.' + json_dumped
# => 1556410547.{"event_type" : "order.created", "date": "2020-06-08".....}
hash = hmac.new(secret.encode(), message.encode(), hashlib.sha256)
hex_digest = hash.hexdigest()
# => 3e4520c869552a282ed29b6523eecbd591fc19d1a3f9e4933e03ae8ce3f77bd4
# hmac_to_verify = 06cc9aab9fd856bdc326f21d54a23e62441adb5966182e784db47ab4f2568231
return hmac.compare_digest(hex_digest, hmac_to_verify)
Im not sure what I am doing wrong. For the other webhooks I am validating, I used base64 encoding, but it seems like here, that hasnt been used on the PHP side. I am not so familiar with PHP so maybe there is something I've missed in how they built the orginal hash. There could be complications coming from the fact that I have to convert back and forth between byte arrays and strings, maybe I am using the wrong encoding for that ? Please someone help, I feel like I've tried every combination and am at a loss.
EDIT : Tried this solution by leaving the body without encoding it in json and it still fails :
print(type(timestamp)
# => <class 'str'>
print(type(body))
# => <class 'bytes'>
# cant concatenate bytes to string...
message = timestamp.encode('utf-8') + b'.' + body
# => b'1556410547.{\n "event_type": "order.created",\n "event_time": "2020-06-08 11:16:04",\n ...
hash = hmac.new(secret.encode(), message, hashlib.sha256)
hex_digest = hash.hexdigest()
# ...etc
EDIT EDIT :
Actually it is working in production ! Thanks to the solution described above (concatenating everything as bytes). My Postman request with the faked webhook was still failing, but that's probably because of how I copied and pasted the webhook data from my heroku logs :) .
I'm getting a POST request inside a Flask app from Slack. The request is sent when a user presses on an interactive message button. According to Slack docs I must extract the body of the request to verify the signature.
My computed signature doesn't match the one sent by Slack, though.
In fact, the body of the request comes as some encoded string. The string is actually an encoded dictionary instead of a query str parameters, as expected.
Here's the beginning of my view:
#app.route('/register', methods=['POST'])
def register_visit():
data = request.get_data()
signature = request.headers.get('X-Slack-Signature', None)
timestamp = request.headers.get('X-Slack-Request-Timestamp', None)
signing_secret = b'aaaaaaaaaaaaaaaa'
# old message, ignore
if round(actual_time.time() - float(timestamp)) > 60 * 5:
return
concatenated = ("v0:%s:%s" % (timestamp, data)).encode('utf-8')
computed_signature = 'v0=' + hmac.new(signing_secret, msg=concatenated, digestmod=hashlib.sha256).hexdigest()
if hmac.compare_digest(computed_signature, signature):
...
I've tried to format the received data to make it look like:
token=fdjkgjl&user_id=1234... but I am not aware of all of the necessary parameters that have to be present in the data.
Any ideas are highly appreciated.
The body of the message is following - after being URL decoded (note I've modified possibly sensitive data):
b'payload={"type":"interactive_message","actions":
[{"name":"yes_button","type":"button","value":"236"}],"callback_id":"visit_button","team":{"id":"fffff","domain":"ffff"},"channel":{"id":"ffff","name":"directmessage"},"user":{"id":"ffffff","name":"fffft"},"action_ts":"1540403943.419120","message_ts":"1541403949.000100","attachment_id":"1","token":"8LpjBuv13J7xAjhl2lEajoBU","is_app_unfurl":false,"original_message":{"text":"Test","bot_id":"DDDDDDDDD","attachments":[{"callback_id":"visit_button","text":"Register","id":1,"color":"3AA3E3","actions":[{"id":"1","name":"yes_button","text":"Yes","type":"button","value":"236","style":""}],"fallback":"Register"}],"type":"message","subtype":"bot_message","ts":"1540413949.000100"},"response_url":"https://hooks.slack.com/actions/ffffff/ffffff/tXJjx1XInaUhrikj6oEzK08e","trigger_id":"464662548327.425084163429.dda35a299eedb940ab98dbb9386b56f0"}'
The reason you are getting the "garbled" data is that you are using request.get_data(). That method will return the raw data of a request, but not do any decoding for you.
Much more convenient is to use request.form.get('payload'), which will directly give you the JSON string of the request object. You can then convert that into a dict object with json.loads() to process it further in your app.
Note that the format you received is the correct format for interactive messages. You will not get a query string (e.g. "token=abc;user_id?def...") as you suggested (like for slash command requests). Interactive message request will always contain the request as JSON string in a payload form property. See here for reference.
Here is a simple working example, which will reply a greeting to the user that pressed the button. It will work directly with Slack, but I recommend using Postman to test it.
#app.py
from flask import Flask, request #import main Flask class and request object
import json
app = Flask(__name__) #create the Flask app
#app.route('/register', methods=['POST'])
def register_visit():
slack_req = json.loads(request.form.get('payload'))
response = '{"text": "Hi, <#' + slack_req["user"]["id"] + '>"}'
return response, 200, {'content-type': 'application/json'}
if __name__ == '__main__':
app.run(debug=True, port=5000) #run app in debug mode on port 5000
OK, the issue wasn't related to how Slack sends me the message. It was about misunderstanding which data comes as bytes and which data is unicode. The culprit was string formatting in my case - the line concatenated = ("v0:%s:%s" % (timestamp, data)).encode('utf-8') should have been concatenated = (b"v0:%b:%b" % (timestamp.encode("utf-8"), data)). Data is already bytes, timestamp meanwhile is unicode.
Cannot believe I've banged my head on this for hours -_-
#app.route('/register', methods=['POST'])
def register_visit():
data = request.get_data()
signature = request.headers.get('X-Slack-Signature', None)
timestamp = request.headers.get('X-Slack-Request-Timestamp', None)
signing_secret = b'aaaaaaaaaaaaaaaa'
# old message, ignore
if round(actual_time.time() - float(timestamp)) > 60 * 5:
return
concatenated = (b"v0:%b:%b" % (timestamp.encode("utf-8"), data))
computed_signature = 'v0=' + hmac.new(signing_secret, msg=concatenated,
digestmod=hashlib.sha256).hexdigest()
if hmac.compare_digest(computed_signature, signature):
...
This worked for me
from urllib import parse
parsed_text = parse.unquote('your bytes text here')
I have the following code of a GET method which takes a photo which is stored in a blob type field in MySql and return. I want to return it to the client inside a JSON string in a type it can display the image in an angularjs application.
def GET(self,r):
user_data = CC.get_data(query) # holds the content of the blob field.
print type(user_data) # prints <type 'str'>
data = {'name': 'test',
'photo': user_data}
return json.dump(data)
This gives,
UnicodeDecodeError: 'utf8' codec can't decode byte 0x89 in position 0:
invalid start byte
I have found in some websites its better to send as photo as byte array.
Im using web.py python framework.
whats the best way to do this?
To prevent data loss, the best thing you can do to send binary data is encode as base64.
import base64
def GET(self,r):
user_data = CC.get_data(query) # holds the content of the blob field.
data = {'name': 'test',
'photo': base64.b64encode(user_data)}
return json.dump(data)
However, sending binary data over JSON is really not recommended, specially in web. You can send a URL to download the photo, for example.
First how to work with blob:
http://www.mysqltutorial.org/python-mysql-blob/
To send your image to your template:
def imageResponseView(...) .... return response
bind url to this view
show image using <img src = "//url_to_that_view" />
From: I have an image's HTTPResponse. How do I display it in a Django template?
I'm trying to do API-request and I need API-key to different view. I'm trying to use session variable, but the key seems to be in some other format than trying to use variable from Sqlite database. API requests work with the key from database, but not with session variable
How I get API-key from database and from session:
key_session = request.session['key']
key_db = APIkey.objects.values_list('key', flat=True).get(pk=2)
Both of these return same values, when I print them. Key example:
3h3asdh-asdasd:oisf87sdf87a5df76asdf83jhjhasgd8
I'm using base64.encodestring function when trying to do authentication to API-service with my key:
query = request.GET.get('query')
url = urllib2.Request('https://api.someapiwebsite.com',
None, headers={'Content-Type':'application/json'})
base64string = base64.encodestring('%s' % (key_session)).replace('\n', '')
If I print base64string with session variable (key_session), I get:
MmoihjsdasdoihhaG5tbjpuq9876eq9asd98a7Nmd3dWYzN2JmbWZ2aW1nMGVw==
If I print base64string with session variable (key_db), only difference is the two last characters == is now 'IC', and I think that's why the authentication to API service is failing:
MmoihjsdasdoihhaG5tbjpuq9876eq9asd98a7Nmd3dWYzN2JmbWZ2aW1nMGVwIC
What is making this difference in the base64 encoded string?
Edit:
I can see difference when using print repr():
print repr(key_db)
3h3asdh-asdasd:oisf87sdf87a5df76asdf83jhjhasgd8
print repr(key_session)
3h3asdh-asdasd:oisf87sdf87a5df76asdf83jhjhasgd8\x02\x02
One of the strings probably contains some trailing characters that print isn't showing. If you use repr then you should be able to see what the difference is.
print(repr(key_session))
print(repr(key_db))
You can then strip any characters as necessary before encoding the string, for example:
key_session = key_session.rstrip('\x02')