Compare commits
No commits in common. "main" and "30b8c4b274ea867ff84711eed8785fd6a9a9160e" have entirely different histories.
main
...
30b8c4b274
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
*.db
|
||||||
|
*.log
|
||||||
|
*/__pycache__/*
|
9
LICENSE
9
LICENSE
@ -1,9 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) <year> <copyright holders>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,3 +0,0 @@
|
|||||||
# chatgpt
|
|
||||||
|
|
||||||
This repository contains my journey to write code with chatgpt, chat.openai.com/chat.
|
|
51
async-rsa-encryption.py
Normal file
51
async-rsa-encryption.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
import json
|
||||||
|
import base64
|
||||||
|
import asyncio
|
||||||
|
from cryptography.fernet import Fernet
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||||
|
|
||||||
|
|
||||||
|
# Generate a new RSA key pair
|
||||||
|
private_key = rsa.generate_private_key()
|
||||||
|
public_key = private_key.public_key()
|
||||||
|
|
||||||
|
|
||||||
|
# Asynchronously encrypt and decrypt a JSON document
|
||||||
|
async def encrypt_decrypt_json(json_data: dict) -> dict:
|
||||||
|
# Convert the JSON data to a string
|
||||||
|
json_str = json.dumps(json_data)
|
||||||
|
|
||||||
|
# Encode the JSON string as bytes
|
||||||
|
json_bytes = json_str.encode()
|
||||||
|
|
||||||
|
# Encrypt the JSON bytes using Fernet
|
||||||
|
fernet = Fernet(base64.urlsafe_b64encode(public_key.public_bytes(
|
||||||
|
encoding=rsa.Encoding.DER,
|
||||||
|
format=rsa.PublicFormat.SubjectPublicKeyInfo
|
||||||
|
)))
|
||||||
|
encrypted_json_bytes = fernet.encrypt(json_bytes)
|
||||||
|
|
||||||
|
# Decrypt the encrypted JSON bytes using Fernet
|
||||||
|
decrypted_json_bytes = fernet.decrypt(encrypted_json_bytes)
|
||||||
|
|
||||||
|
# Decode the decrypted JSON bytes back to a string
|
||||||
|
decrypted_json_str = decrypted_json_bytes.decode()
|
||||||
|
|
||||||
|
# Convert the decrypted JSON string back to a dictionary
|
||||||
|
decrypted_json_data = json.loads(decrypted_json_str)
|
||||||
|
|
||||||
|
return decrypted_json_data
|
||||||
|
|
||||||
|
|
||||||
|
# Example usage
|
||||||
|
json_data = {
|
||||||
|
"user": "johnsmith",
|
||||||
|
"password": "correcthorsebatterystaple"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Asynchronously encrypt and decrypt the JSON data
|
||||||
|
decrypted_json_data = asyncio.run(encrypt_decrypt_json(json_data))
|
||||||
|
|
||||||
|
# Print the decrypted JSON
|
||||||
|
|
104
bitcoin-price-database.py
Executable file
104
bitcoin-price-database.py
Executable file
@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import sqlite3
|
||||||
|
import requests
|
||||||
|
import matplotlib
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import matplotlib.animation as animation
|
||||||
|
import matplotlib.style as style
|
||||||
|
|
||||||
|
def Checkthedatabase():
|
||||||
|
## Some sanity for the database
|
||||||
|
# check if btc_timeseries.db database file exists
|
||||||
|
if not os.path.exists("btc_timeseries.db"):
|
||||||
|
db = sqlite3.connect("btc_timeseries.db")
|
||||||
|
db.execute("CREATE TABLE timeseries (timestamp INTEGER, value REAL)")
|
||||||
|
db.commit()
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
db = sqlite3.connect("btc_timeseries.db")
|
||||||
|
|
||||||
|
# Check if the table exists
|
||||||
|
table_exists = False
|
||||||
|
cursor = db.execute("PRAGMA table_info(timeseries)")
|
||||||
|
for row in cursor:
|
||||||
|
table_exists = True
|
||||||
|
|
||||||
|
# Create the table if it doesn't exist
|
||||||
|
if not table_exists:
|
||||||
|
db.execute("CREATE TABLE timeseries (timestamp INTEGER, value REAL)")
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
def Getdata():
|
||||||
|
#fetch the price data
|
||||||
|
payload = {'symbol': 'BTCUSDT'}
|
||||||
|
response = requests.get('https://api.binance.com/api/v3/avgPrice', params=payload)
|
||||||
|
|
||||||
|
#get the usd_value
|
||||||
|
json_data = response.json()
|
||||||
|
usd_value = json_data['price']
|
||||||
|
|
||||||
|
### Insert the USD value into the database
|
||||||
|
db.execute("INSERT INTO timeseries (timestamp, value) VALUES (datetime('now'), ?)", (usd_value,))
|
||||||
|
|
||||||
|
## Save the changes to the database
|
||||||
|
db.commit()
|
||||||
|
#print(db.execute("SELECT * FROM timeseries"))
|
||||||
|
|
||||||
|
#update the graph
|
||||||
|
def Updategraph(num):
|
||||||
|
cursor.execute("SELECT timestamp, value FROM timeseries WHERE timestamp > datetime('now', '-10 second')")
|
||||||
|
stuff = cursor.fetchall()
|
||||||
|
|
||||||
|
timestamps = [row[0] for row in stuff]
|
||||||
|
values = [row[1] for row in stuff]
|
||||||
|
|
||||||
|
line.set_data(timestamps, values)
|
||||||
|
ax.relim()
|
||||||
|
ax.autoscale_view()
|
||||||
|
Getdata()
|
||||||
|
|
||||||
|
Checkthedatabase()
|
||||||
|
|
||||||
|
db = sqlite3.connect("btc_timeseries.db")
|
||||||
|
Getdata()
|
||||||
|
|
||||||
|
##some styling for the plot
|
||||||
|
style.use('dark_background')
|
||||||
|
|
||||||
|
colors = {
|
||||||
|
'figure.facecolor': '#222222',
|
||||||
|
'axes.facecolor': '#222222',
|
||||||
|
'axes.edgecolor': '#FFFFFF',
|
||||||
|
'axes.labelcolor': '#FFFFFF',
|
||||||
|
'grid.color': '#444444',
|
||||||
|
'grid.linestyle': 'dotted',
|
||||||
|
'lines.color': '#FFFFFF'
|
||||||
|
}
|
||||||
|
matplotlib.rcParams.update(colors)
|
||||||
|
|
||||||
|
# Create a figure and axes for the plot
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
|
||||||
|
#query database for the data
|
||||||
|
cursor = db.execute("SELECT timestamp, value FROM timeseries")
|
||||||
|
|
||||||
|
stuff = cursor.fetchall()
|
||||||
|
# Extract the timestamp and value columns from the query result
|
||||||
|
timestamps = [row[0] for row in stuff]
|
||||||
|
values = [row[1] for row in stuff]
|
||||||
|
|
||||||
|
# Create a line plot using the time series data
|
||||||
|
line, = ax.plot(timestamps, values)
|
||||||
|
plt.plot(timestamps, values)
|
||||||
|
|
||||||
|
# Create an animation using the update function
|
||||||
|
ani = animation.FuncAnimation(fig, Updategraph, interval=60000)
|
||||||
|
|
||||||
|
# Show the plot
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
db.close()
|
||||||
|
exit(0)
|
BIN
btc_timeseries.db
Normal file
BIN
btc_timeseries.db
Normal file
Binary file not shown.
5
btc_tracker.py
Normal file
5
btc_tracker.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import fetcher
|
||||||
|
|
||||||
|
fetcher.start()
|
||||||
|
|
||||||
|
exit(0)
|
BIN
btc_tracker/database
Normal file
BIN
btc_tracker/database
Normal file
Binary file not shown.
16
btc_tracker/fetch_data.py
Executable file
16
btc_tracker/fetch_data.py
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
import json, time
|
||||||
|
|
||||||
|
# Load the JSON file
|
||||||
|
with open('sources.json', 'r') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
# Iterate over the exchanges
|
||||||
|
for exchange in data['exchanges']:
|
||||||
|
# Print the name and URL of the exchange
|
||||||
|
if exchange['name'] == "Kraken":
|
||||||
|
current_time = int(time.time()) - 300
|
||||||
|
exchange['url'] += f"&since={current_time}"
|
||||||
|
print(exchange['name'], exchange['url'])
|
||||||
|
else:
|
||||||
|
print(exchange['name'], exchange['url'])
|
228
btc_tracker/fetcher.py
Executable file
228
btc_tracker/fetcher.py
Executable file
@ -0,0 +1,228 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import krakenex
|
||||||
|
import json, sqlite3
|
||||||
|
import requests, os, time
|
||||||
|
import threading
|
||||||
|
|
||||||
|
database = "btc_ohlc.db"
|
||||||
|
|
||||||
|
def Checkthedatabase():
|
||||||
|
## Some sanity for the database
|
||||||
|
# check if btc_timeseries.db database file exists
|
||||||
|
if not os.path.exists(database):
|
||||||
|
db = sqlite3.connect(database)
|
||||||
|
|
||||||
|
db.execute("""\
|
||||||
|
CREATE TABLE ohlc (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
exchange TEXT NOT NULL,
|
||||||
|
timestamp INTEGER NOT NULL,
|
||||||
|
open REAL NOT NULL,
|
||||||
|
high REAL NOT NULL,
|
||||||
|
low REAL NOT NULL,
|
||||||
|
close REAL NOT NULL,
|
||||||
|
volume_quote REAL NOT NULL,
|
||||||
|
volume_base REAL NOT NULL,
|
||||||
|
trades INTEGER NOT NULL )""")
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
db = sqlite3.connect(database)
|
||||||
|
|
||||||
|
# Check if the table exists
|
||||||
|
table_exists = False
|
||||||
|
cursor = db.execute("PRAGMA table_info(ohlc)")
|
||||||
|
for row in cursor:
|
||||||
|
table_exists = True
|
||||||
|
|
||||||
|
# Create the table if it doesn't exist
|
||||||
|
if not table_exists:
|
||||||
|
db.execute("""\
|
||||||
|
CREATE TABLE ohlc (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
exchange TEXT NOT NULL,
|
||||||
|
timestamp INTEGER NOT NULL,
|
||||||
|
open REAL NOT NULL,
|
||||||
|
high REAL NOT NULL,
|
||||||
|
low REAL NOT NULL,
|
||||||
|
close REAL NOT NULL,
|
||||||
|
volume_quote REAL NOT NULL,
|
||||||
|
volume_base REAL NOT NULL,
|
||||||
|
trades INTEGER NOT NULL )""")
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
def fetch_kraken():
|
||||||
|
### Kraken
|
||||||
|
kraken = krakenex.API()
|
||||||
|
|
||||||
|
response = kraken.query_public('OHLC', {'pair': 'BTCUSD', 'interval': 240 })
|
||||||
|
ohlc_data = response['result']['XXBTZUSD']
|
||||||
|
|
||||||
|
candle_stick_data = {
|
||||||
|
'exchange': 'kraken',
|
||||||
|
'timestamp': ohlc_data[1][0],
|
||||||
|
'open': ohlc_data[0][1],
|
||||||
|
'high': max(item[2] for item in ohlc_data),
|
||||||
|
'low': min(item[3] for item in ohlc_data),
|
||||||
|
'close': ohlc_data[-1][4],
|
||||||
|
'volume_quote': sum(float(item[5]) for item in ohlc_data),
|
||||||
|
'volume_base': sum(float(item[6]) for item in ohlc_data),
|
||||||
|
'trades': sum(item[7] for item in ohlc_data),
|
||||||
|
}
|
||||||
|
|
||||||
|
kraken_json = json.dumps(candle_stick_data, indent=2)
|
||||||
|
#print("Kraken: OK")
|
||||||
|
#print(kraken_json)
|
||||||
|
#q.put("Kraken: OK")
|
||||||
|
return kraken_json
|
||||||
|
|
||||||
|
def fetch_bitstamp(q):
|
||||||
|
## Bitstamp
|
||||||
|
response = requests.get("https://www.bitstamp.net/api/v2/ohlc/btcusd/?step=300&limit=1")
|
||||||
|
|
||||||
|
if response.status_code == 200: # check if the request was successful
|
||||||
|
bitstamp_data = response.json()
|
||||||
|
ohlc_data = bitstamp_data["data"]["ohlc"]
|
||||||
|
|
||||||
|
candle_stick_data = {
|
||||||
|
'exchange': 'bitstamp',
|
||||||
|
'timestamp': int(ohlc_data[0]['timestamp']),
|
||||||
|
'open': float(ohlc_data[0]['open']),
|
||||||
|
'high': float(ohlc_data[0]['high']),
|
||||||
|
'low': float(ohlc_data[0]['low']),
|
||||||
|
'close': float(ohlc_data[0]['close']),
|
||||||
|
'volume_quote': float(ohlc_data[0]['volume']),
|
||||||
|
'volume_base': 0, # not provided by Bitstamp API
|
||||||
|
'trades': 0, # not provided by Bitstamp API
|
||||||
|
}
|
||||||
|
|
||||||
|
bitstamp_json = json.dumps(candle_stick_data, indent=2)
|
||||||
|
#print("Bitstamp: OK")
|
||||||
|
#print(bitstamp_json)
|
||||||
|
#q.put("Bitstamp: OK")
|
||||||
|
return bitstamp_json
|
||||||
|
else:
|
||||||
|
print(f"Error fetching data from Bitstamp API: {response.status_code}")
|
||||||
|
q.put("Bitstamp: ERROR")
|
||||||
|
return empty_json
|
||||||
|
|
||||||
|
def fetch_bitfinex(q):
|
||||||
|
## Bitfinex
|
||||||
|
response = requests.get("https://api-pub.bitfinex.com/v2/candles/trade:5m:tBTCUSD/last")
|
||||||
|
|
||||||
|
if response.status_code == 200: # check if the request was successful
|
||||||
|
ohlc_data = response.json()
|
||||||
|
candle_stick_data = {
|
||||||
|
'exchange': 'bitfinex',
|
||||||
|
'timestamp': ohlc_data[0],
|
||||||
|
'open': ohlc_data[1],
|
||||||
|
'high': ohlc_data[2],
|
||||||
|
'low': ohlc_data[3],
|
||||||
|
'close': ohlc_data[4],
|
||||||
|
'volume_quote': ohlc_data[5],
|
||||||
|
'volume_base': 0, # not provided by Bitfinex API
|
||||||
|
'trades': 0, # not provided by Bitfinex API
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfinex_json = json.dumps(candle_stick_data, indent=2)
|
||||||
|
#print("Bitfinex: OK")
|
||||||
|
#print(bitfinex_json)
|
||||||
|
#q.put("Bitfinex: OK")
|
||||||
|
return bitfinex_json
|
||||||
|
else:
|
||||||
|
print(f"Error fetching data from Bitfinex API: {response.status_code}")
|
||||||
|
q.put("Bitfinex: ERROR")
|
||||||
|
return empty_json
|
||||||
|
|
||||||
|
def fetch_gemini(q):
|
||||||
|
## Gemini
|
||||||
|
response = requests.get("https://api.gemini.com/v2/candles/btcusd/5m")
|
||||||
|
|
||||||
|
if response.status_code == 200: # check if the request was successful
|
||||||
|
gemini_ohlc = response.json()
|
||||||
|
candle_stick_data = {
|
||||||
|
'exchange': 'gemini',
|
||||||
|
'timestamp': gemini_ohlc[0][0],
|
||||||
|
'open': gemini_ohlc[0][1],
|
||||||
|
'high': gemini_ohlc[0][2],
|
||||||
|
'low': gemini_ohlc[0][3],
|
||||||
|
'close': gemini_ohlc[0][4],
|
||||||
|
'volume_quote': 0, # not provided by Gemini API
|
||||||
|
'volume_base': gemini_ohlc[0][5],
|
||||||
|
'trades': 0, # not provided by Gemini API
|
||||||
|
}
|
||||||
|
gemini_json = json.dumps(candle_stick_data, indent=2)
|
||||||
|
#print("Gemini: OK")
|
||||||
|
#print(gemini_json)
|
||||||
|
#q.put("Gemini: OK")
|
||||||
|
return gemini_json
|
||||||
|
else:
|
||||||
|
print(f"Error fetching data from Gemini API: {response.status_code}")
|
||||||
|
q.put("Gemini: ERROR")
|
||||||
|
return empty_json
|
||||||
|
|
||||||
|
def write_dict_to_database(in_dict, connection):
|
||||||
|
cursor = connection.cursor()
|
||||||
|
# Use placeholders for the values in the INSERT statement
|
||||||
|
insert_query = "INSERT INTO ohlc (exchange, timestamp, open, high, low, close, volume_quote, volume_base, trades) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
||||||
|
|
||||||
|
values = (in_dict['exchange'],
|
||||||
|
in_dict['timestamp'],
|
||||||
|
in_dict['open'],
|
||||||
|
in_dict['high'],
|
||||||
|
in_dict['low'],
|
||||||
|
in_dict['close'],
|
||||||
|
in_dict['volume_quote'],
|
||||||
|
in_dict['volume_base'],
|
||||||
|
in_dict['trades'])
|
||||||
|
## apply lock while writing to database
|
||||||
|
with database_lock:
|
||||||
|
cursor.execute(insert_query, values)
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
def get_the_data(q):
|
||||||
|
#cursor = db.cursor()
|
||||||
|
while True:
|
||||||
|
#logline = "Fetching at: " + str(time.time())
|
||||||
|
#q.put(logline)
|
||||||
|
db = sqlite3.connect(database)
|
||||||
|
write_dict_to_database(json.loads(fetch_kraken()), db)
|
||||||
|
write_dict_to_database(json.loads(fetch_bitfinex(q)), db)
|
||||||
|
write_dict_to_database(json.loads(fetch_bitstamp(q)), db)
|
||||||
|
write_dict_to_database(json.loads(fetch_gemini(q)), db)
|
||||||
|
db.close()
|
||||||
|
time.sleep(290)
|
||||||
|
|
||||||
|
|
||||||
|
Checkthedatabase()
|
||||||
|
|
||||||
|
# Empty response json
|
||||||
|
empty_dict = {"exchange": "", "timestamp": 0, "open": 0, "high": 0, "low": 0, "close": 0, "volume_quote": 0, "volume_base": 0, "trades": 0}
|
||||||
|
empty_json = json.dumps(empty_dict)
|
||||||
|
database_lock = threading.Lock()
|
||||||
|
|
||||||
|
fetch_thread = threading.Thread()
|
||||||
|
def get_health():
|
||||||
|
if fetch_thread.is_alive():
|
||||||
|
return "Alive"
|
||||||
|
else:
|
||||||
|
return "Dead"
|
||||||
|
|
||||||
|
def start(q):
|
||||||
|
logline = "Started at " + str(time.time())
|
||||||
|
q.put(logline)
|
||||||
|
fetch_thread.target = get_the_data
|
||||||
|
fetch_thread.args = (q, )
|
||||||
|
fetch_thread.daemon = True
|
||||||
|
fetch_thread.start()
|
||||||
|
logline = "Fetcher ID: " + str(fetch_thread.ident) + " or " + str(fetch_thread.native_id)
|
||||||
|
q.put(logline)
|
||||||
|
|
||||||
|
db = sqlite3.connect(database)
|
||||||
|
lastID_andTime = db.execute("SELECT id, timestamp FROM ohlc LIMIT 1 OFFSET (SELECT COUNT(*) FROM ohlc) - 1").fetchall()
|
||||||
|
#q.put(json.dumps(lastID_andTime, indent=2, separators=(',', ':')))
|
||||||
|
q.put(json.dumps(lastID_andTime, separators=(',', ':')))
|
||||||
|
|
||||||
|
|
235
btc_tracker/kraken_fetch.py
Executable file
235
btc_tracker/kraken_fetch.py
Executable file
@ -0,0 +1,235 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import krakenex
|
||||||
|
import json, sqlite3
|
||||||
|
import requests, os, time
|
||||||
|
import threading
|
||||||
|
from flask import Flask, request
|
||||||
|
|
||||||
|
database = "btc_ohlc.db"
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
database_lock = threading.Lock()
|
||||||
|
|
||||||
|
# Empty response json
|
||||||
|
empty_dict = {"exchange": "", "timestamp": 0, "open": 0, "high": 0, "low": 0, "close": 0, "volume_quote": 0, "volume_base": 0, "trades": 0}
|
||||||
|
empty_json = json.dumps(empty_dict)
|
||||||
|
|
||||||
|
def Checkthedatabase():
|
||||||
|
## Some sanity for the database
|
||||||
|
# check if btc_timeseries.db database file exists
|
||||||
|
if not os.path.exists(database):
|
||||||
|
db = sqlite3.connect(database)
|
||||||
|
|
||||||
|
db.execute("""\
|
||||||
|
CREATE TABLE ohlc (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
exchange TEXT NOT NULL,
|
||||||
|
timestamp INTEGER NOT NULL,
|
||||||
|
open REAL NOT NULL,
|
||||||
|
high REAL NOT NULL,
|
||||||
|
low REAL NOT NULL,
|
||||||
|
close REAL NOT NULL,
|
||||||
|
volume_quote REAL NOT NULL,
|
||||||
|
volume_base REAL NOT NULL,
|
||||||
|
trades INTEGER NOT NULL )""")
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
db = sqlite3.connect(database)
|
||||||
|
|
||||||
|
# Check if the table exists
|
||||||
|
table_exists = False
|
||||||
|
cursor = db.execute("PRAGMA table_info(ohlc)")
|
||||||
|
for row in cursor:
|
||||||
|
table_exists = True
|
||||||
|
|
||||||
|
# Create the table if it doesn't exist
|
||||||
|
if not table_exists:
|
||||||
|
db.execute("""\
|
||||||
|
CREATE TABLE ohlc (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
exchange TEXT NOT NULL,
|
||||||
|
timestamp INTEGER NOT NULL,
|
||||||
|
open REAL NOT NULL,
|
||||||
|
high REAL NOT NULL,
|
||||||
|
low REAL NOT NULL,
|
||||||
|
close REAL NOT NULL,
|
||||||
|
volume_quote REAL NOT NULL,
|
||||||
|
volume_base REAL NOT NULL,
|
||||||
|
trades INTEGER NOT NULL )""")
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
def fetch_kraken():
|
||||||
|
### Kraken
|
||||||
|
kraken = krakenex.API()
|
||||||
|
|
||||||
|
response = kraken.query_public('OHLC', {'pair': 'BTCUSD', 'interval': 240 })
|
||||||
|
ohlc_data = response['result']['XXBTZUSD']
|
||||||
|
|
||||||
|
candle_stick_data = {
|
||||||
|
'exchange': 'kraken',
|
||||||
|
'timestamp': ohlc_data[1][0],
|
||||||
|
'open': ohlc_data[0][1],
|
||||||
|
'high': max(item[2] for item in ohlc_data),
|
||||||
|
'low': min(item[3] for item in ohlc_data),
|
||||||
|
'close': ohlc_data[-1][4],
|
||||||
|
'volume_quote': sum(float(item[5]) for item in ohlc_data),
|
||||||
|
'volume_base': sum(float(item[6]) for item in ohlc_data),
|
||||||
|
'trades': sum(item[7] for item in ohlc_data),
|
||||||
|
}
|
||||||
|
|
||||||
|
kraken_json = json.dumps(candle_stick_data, indent=2)
|
||||||
|
#print("Kraken: OK")
|
||||||
|
#print(kraken_json)
|
||||||
|
return kraken_json
|
||||||
|
|
||||||
|
def fetch_bitstamp():
|
||||||
|
## Bitstamp
|
||||||
|
response = requests.get("https://www.bitstamp.net/api/v2/ohlc/btcusd/?step=300&limit=1")
|
||||||
|
|
||||||
|
if response.status_code == 200: # check if the request was successful
|
||||||
|
bitstamp_data = response.json()
|
||||||
|
ohlc_data = bitstamp_data["data"]["ohlc"]
|
||||||
|
|
||||||
|
candle_stick_data = {
|
||||||
|
'exchange': 'bitstamp',
|
||||||
|
'timestamp': int(ohlc_data[0]['timestamp']),
|
||||||
|
'open': float(ohlc_data[0]['open']),
|
||||||
|
'high': float(ohlc_data[0]['high']),
|
||||||
|
'low': float(ohlc_data[0]['low']),
|
||||||
|
'close': float(ohlc_data[0]['close']),
|
||||||
|
'volume_quote': float(ohlc_data[0]['volume']),
|
||||||
|
'volume_base': 0, # not provided by Bitstamp API
|
||||||
|
'trades': 0, # not provided by Bitstamp API
|
||||||
|
}
|
||||||
|
|
||||||
|
bitstamp_json = json.dumps(candle_stick_data, indent=2)
|
||||||
|
#print("Bitstamp: OK")
|
||||||
|
# print(bitstamp_json)
|
||||||
|
return bitstamp_json
|
||||||
|
else:
|
||||||
|
print(f"Error fetching data from Bitstamp API: {response.status_code}")
|
||||||
|
return empty_json
|
||||||
|
|
||||||
|
def fetch_bitfinex():
|
||||||
|
## Bitfinex
|
||||||
|
response = requests.get("https://api-pub.bitfinex.com/v2/candles/trade:5m:tBTCUSD/last")
|
||||||
|
|
||||||
|
if response.status_code == 200: # check if the request was successful
|
||||||
|
ohlc_data = response.json()
|
||||||
|
candle_stick_data = {
|
||||||
|
'exchange': 'bitfinex',
|
||||||
|
'timestamp': ohlc_data[0],
|
||||||
|
'open': ohlc_data[1],
|
||||||
|
'high': ohlc_data[2],
|
||||||
|
'low': ohlc_data[3],
|
||||||
|
'close': ohlc_data[4],
|
||||||
|
'volume_quote': ohlc_data[5],
|
||||||
|
'volume_base': 0, # not provided by Bitfinex API
|
||||||
|
'trades': 0, # not provided by Bitfinex API
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfinex_json = json.dumps(candle_stick_data, indent=2)
|
||||||
|
#print("Bitfinex: OK")
|
||||||
|
#print(bitfinex_json)
|
||||||
|
return bitfinex_json
|
||||||
|
else:
|
||||||
|
print(f"Error fetching data from Bitfinex API: {response.status_code}")
|
||||||
|
return empty_json
|
||||||
|
|
||||||
|
def fetch_gemini():
|
||||||
|
## Gemini
|
||||||
|
response = requests.get("https://api.gemini.com/v2/candles/btcusd/5m")
|
||||||
|
|
||||||
|
if response.status_code == 200: # check if the request was successful
|
||||||
|
gemini_ohlc = response.json()
|
||||||
|
candle_stick_data = {
|
||||||
|
'exchange': 'gemini',
|
||||||
|
'timestamp': gemini_ohlc[0][0],
|
||||||
|
'open': gemini_ohlc[0][1],
|
||||||
|
'high': gemini_ohlc[0][2],
|
||||||
|
'low': gemini_ohlc[0][3],
|
||||||
|
'close': gemini_ohlc[0][4],
|
||||||
|
'volume_quote': 0, # not provided by Gemini API
|
||||||
|
'volume_base': gemini_ohlc[0][5],
|
||||||
|
'trades': 0, # not provided by Gemini API
|
||||||
|
}
|
||||||
|
gemini_json = json.dumps(candle_stick_data, indent=2)
|
||||||
|
#print("Gemini: OK")
|
||||||
|
#print(gemini_json)
|
||||||
|
return gemini_json
|
||||||
|
else:
|
||||||
|
print(f"Error fetching data from Gemini API: {response.status_code}")
|
||||||
|
return empty_json
|
||||||
|
|
||||||
|
def write_dict_to_database(in_dict, connection):
|
||||||
|
cursor = connection.cursor()
|
||||||
|
# Use placeholders for the values in the INSERT statement
|
||||||
|
insert_query = "INSERT INTO ohlc (exchange, timestamp, open, high, low, close, volume_quote, volume_base, trades) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
||||||
|
|
||||||
|
values = (in_dict['exchange'],
|
||||||
|
in_dict['timestamp'],
|
||||||
|
in_dict['open'],
|
||||||
|
in_dict['high'],
|
||||||
|
in_dict['low'],
|
||||||
|
in_dict['close'],
|
||||||
|
in_dict['volume_quote'],
|
||||||
|
in_dict['volume_base'],
|
||||||
|
in_dict['trades'])
|
||||||
|
## apply lock while writing to database
|
||||||
|
with database_lock:
|
||||||
|
cursor.execute(insert_query, values)
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
def get_the_data():
|
||||||
|
#cursor = db.cursor()
|
||||||
|
while True:
|
||||||
|
db = sqlite3.connect(database)
|
||||||
|
write_dict_to_database(json.loads(fetch_kraken()), db)
|
||||||
|
write_dict_to_database(json.loads(fetch_bitfinex()), db)
|
||||||
|
write_dict_to_database(json.loads(fetch_bitstamp()), db)
|
||||||
|
write_dict_to_database(json.loads(fetch_gemini()), db)
|
||||||
|
db.close()
|
||||||
|
print("fetches done at", time.time(), "sleeping now for 290")
|
||||||
|
time.sleep(290)
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def get_data():
|
||||||
|
# Get the time (t) argument from the url"
|
||||||
|
query_timestamp = request.args.get('t')
|
||||||
|
query_pretty = request.args.get('pretty')
|
||||||
|
|
||||||
|
database_lock.acquire()
|
||||||
|
db = sqlite3.connect(database)
|
||||||
|
if query_timestamp:
|
||||||
|
rows = db.execute("SELECT exchange, timestamp, open, high, low, close FROM ohlc WHERE timestamp > ?", (query_timestamp,)).fetchall()
|
||||||
|
else:
|
||||||
|
rows = db.execute('SELECT exchange, timestamp, open, high, low, close FROM ohlc').fetchall()
|
||||||
|
query_timestamp = 0
|
||||||
|
|
||||||
|
database_lock.release()
|
||||||
|
data = {
|
||||||
|
"timestamp": time.time(),
|
||||||
|
"rows": rows
|
||||||
|
}
|
||||||
|
|
||||||
|
if query_pretty:
|
||||||
|
response = json.dumps(data, indent=2, separators=(';\n', ' :'))
|
||||||
|
else:
|
||||||
|
response = json.dumps(data)
|
||||||
|
|
||||||
|
return response, 200, {'Content-Type': 'application/json'}
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Make sanity checks for the database
|
||||||
|
Checkthedatabase()
|
||||||
|
|
||||||
|
# Start the data fetching backend process
|
||||||
|
fetch_thread = threading.Thread(target=get_the_data)
|
||||||
|
fetch_thread.daemon = True
|
||||||
|
fetch_thread.start()
|
||||||
|
|
||||||
|
# Start the Flask app
|
||||||
|
app.run()
|
24
btc_tracker/sources.json
Normal file
24
btc_tracker/sources.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"exchanges": [
|
||||||
|
{
|
||||||
|
"name": "Bitstamp",
|
||||||
|
"url": "https://www.bitstamp.net/api/v2/ohlc/btcusd/?step=300&limit=1",
|
||||||
|
"freq": "5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Kraken",
|
||||||
|
"url": "https://api.kraken.com/0/public/OHLC?pair=XBTUSD&interval=240",
|
||||||
|
"freq": "5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bitfinex",
|
||||||
|
"url": "https://api-pub.bitfinex.com/v2/candles/trade:5m:tBTCUSD/last",
|
||||||
|
"freq": "5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gemini",
|
||||||
|
"url": "https://api.gemini.com/v2/candles/btcusd/5m",
|
||||||
|
"freg": "5"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
31
btc_tracker/the_server.py
Executable file
31
btc_tracker/the_server.py
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
import fetcher
|
||||||
|
import time
|
||||||
|
from queue import Queue
|
||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
|
||||||
|
# Create a queue to get some info how the fetcher is doing
|
||||||
|
q = Queue()
|
||||||
|
# Start the data collecting
|
||||||
|
fetcher.start(q)
|
||||||
|
|
||||||
|
# Initialize the Flask app
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def root():
|
||||||
|
if not q.empty():
|
||||||
|
data = q.get()
|
||||||
|
return(str(data))
|
||||||
|
else:
|
||||||
|
return("Fetcher message queue is empty")
|
||||||
|
|
||||||
|
@app.route("/fetcher_health")
|
||||||
|
def fetcher_health():
|
||||||
|
health = fetcher.get_health()
|
||||||
|
return(str(health))
|
||||||
|
|
||||||
|
# Run the app
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
25
data-arbiter-todo
Normal file
25
data-arbiter-todo
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
from flask import Flask
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
# Create a route for the web server
|
||||||
|
@app.route('/')
|
||||||
|
def serve_data():
|
||||||
|
# Connect to the database
|
||||||
|
db = sqlite3.connect("btc_timeseries.db")
|
||||||
|
|
||||||
|
# Fetch the data from the database
|
||||||
|
cursor = db.execute("SELECT * FROM timeseries")
|
||||||
|
data = cursor.fetchall()
|
||||||
|
|
||||||
|
# Convert the data to JSON format
|
||||||
|
data_json = json.dumps(data)
|
||||||
|
|
||||||
|
# Return the data as a response to the request
|
||||||
|
return data_json
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Run the web server
|
||||||
|
app.run()
|
||||||
|
|
88
data-arbiter.py
Executable file
88
data-arbiter.py
Executable file
@ -0,0 +1,88 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import os, time
|
||||||
|
import json, math
|
||||||
|
import sqlite3
|
||||||
|
import requests
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
def Checkthedatabase():
|
||||||
|
## Some sanity for the database
|
||||||
|
# check if btc_timeseries.db database file exists
|
||||||
|
if not os.path.exists("btc_timeseries.db"):
|
||||||
|
db = sqlite3.connect("btc_timeseries.db")
|
||||||
|
db.execute("CREATE TABLE timeseries (timestamp INTEGER, value REAL, mins INTEGER, source TEXT)")
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
db = sqlite3.connect("btc_timeseries.db")
|
||||||
|
|
||||||
|
# Check if the table exists
|
||||||
|
table_exists = False
|
||||||
|
cursor = db.execute("PRAGMA table_info(timeseries)")
|
||||||
|
for row in cursor:
|
||||||
|
table_exists = True
|
||||||
|
|
||||||
|
# Create the table if it doesn't exist
|
||||||
|
if not table_exists:
|
||||||
|
db.execute("CREATE TABLE timeseries (timestamp INTEGER, value REAL, mins INTEGER, source TEXT)")
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
def Getdata():
|
||||||
|
#fetch the price data
|
||||||
|
source = 'http://api.binance.com/api/v3/avgPrice'
|
||||||
|
payload = {'symbol': 'BTCUSDT'}
|
||||||
|
response = requests.get(source, params=payload)
|
||||||
|
|
||||||
|
#get the usd_value
|
||||||
|
json_data = response.json()
|
||||||
|
usd_value = json_data['price']
|
||||||
|
mins = json_data['mins']
|
||||||
|
|
||||||
|
### Insert the USD value into the database
|
||||||
|
db.execute("INSERT INTO timeseries (timestamp, value, mins, source) VALUES (datetime('now'), ?, ?, ?)", (usd_value, mins, source))
|
||||||
|
|
||||||
|
## Save the changes to the database
|
||||||
|
db.commit()
|
||||||
|
#print(db.execute("SELECT * FROM timeseries"))
|
||||||
|
|
||||||
|
def Calculatetimesince():
|
||||||
|
cursor = db.execute("SELECT * FROM timeseries ORDER BY timestamp DESC LIMIT 1")
|
||||||
|
stuff = cursor.fetchall()
|
||||||
|
|
||||||
|
timestamp = stuff[0][0]
|
||||||
|
mins = stuff[0][2]
|
||||||
|
|
||||||
|
timenow = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
dt1 = datetime.strptime(timenow, "%Y-%m-%d %H:%M:%S")
|
||||||
|
dt2 = datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S")
|
||||||
|
delta = dt1 - dt2
|
||||||
|
minutedelta = divmod(delta.total_seconds(), 60)
|
||||||
|
minutessince = math.trunc(minutedelta[0])
|
||||||
|
|
||||||
|
|
||||||
|
# if minutes since last run is larger than mins we should get new data
|
||||||
|
print(minutessince, ' - ', mins)
|
||||||
|
if minutessince <= mins:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
Checkthedatabase()
|
||||||
|
|
||||||
|
db = sqlite3.connect("btc_timeseries.db")
|
||||||
|
Getdata()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# Check if it's time to run again
|
||||||
|
mayberun = Calculatetimesince()
|
||||||
|
# we go on 1
|
||||||
|
print(datetime.now(), 'We go on 1, should we go:', mayberun)
|
||||||
|
if mayberun == 1:
|
||||||
|
Getdata()
|
||||||
|
|
||||||
|
time.sleep(20)
|
||||||
|
|
||||||
|
db.close()
|
||||||
|
exit(0)
|
60
demo-client.py
Executable file
60
demo-client.py
Executable file
@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from hashlib import sha256
|
||||||
|
import ecdsa
|
||||||
|
|
||||||
|
private_key = '03486537091ceb021fb313e5cf3eb04d44ca2f19f72112a1'
|
||||||
|
# we need to send server:
|
||||||
|
# the question: domain.tld/get/<id>
|
||||||
|
# the checksum: ?sum=sha256
|
||||||
|
# the signed data: header 'auth'
|
||||||
|
|
||||||
|
id = 123
|
||||||
|
url = 'localhost:5000/get/'
|
||||||
|
url_id = url + str(id)
|
||||||
|
sum = sha256(url_id.encode('ascii')).hexdigest()
|
||||||
|
reg_url = 'http://' + url_id + '?sum=' + sum
|
||||||
|
|
||||||
|
unsigned_data = url_id + '?' + 'sum=' + sum
|
||||||
|
|
||||||
|
# Generate SK from the private key
|
||||||
|
private_key_int = int(private_key, 16)
|
||||||
|
sk = ecdsa.SigningKey.from_secret_exponent(private_key_int, curve=ecdsa.SECP256k1)
|
||||||
|
|
||||||
|
# sign the message
|
||||||
|
signature = sk.sign(unsigned_data.encode('utf-8'))
|
||||||
|
signature_hex = signature.hex()
|
||||||
|
|
||||||
|
print('we signed: ', unsigned_data)
|
||||||
|
print('We will send:')
|
||||||
|
print('to: ', reg_url)
|
||||||
|
print('sum: ', sum)
|
||||||
|
print('auth: ', signature_hex)
|
||||||
|
print('------------------------')
|
||||||
|
|
||||||
|
response = requests.get(reg_url, headers={"auth":signature_hex})
|
||||||
|
print('>>> ', response.status_code)
|
||||||
|
print('>>> ', response.content)
|
||||||
|
|
||||||
|
#ecdsa_public_key = '8716c78c09a4e4571a3112eca1c7ddce41289e20da446894b621f2a11ba91bc963f2e9fb9ddd5552c26faf814bc582b4'
|
||||||
|
ecdsa_public_key = '068716c78c09a4e4571a3112eca1c7ddce41289e20da446894b621f2a11ba91bc963f2e9fb9ddd5552c26faf814bc582b4'
|
||||||
|
|
||||||
|
bytes_public_key = bytes.fromhex(ecdsa_public_key)
|
||||||
|
|
||||||
|
bytes_signed_data = signature_hex.encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
vk = ecdsa.VerifyingKey.from_string(bytes_public_key, curve=ecdsa.SECP256k1)
|
||||||
|
|
||||||
|
if vk.verify(signature_hex, unsigned_data):
|
||||||
|
response = "YES"
|
||||||
|
else:
|
||||||
|
response = "NO"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
exit(0)
|
49
encryption-on-apis/ecdsa-example-test.py
Executable file
49
encryption-on-apis/ecdsa-example-test.py
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import ecdsa, binascii, sys
|
||||||
|
from hashlib import sha256
|
||||||
|
|
||||||
|
message = 'Hello public/private key world!'
|
||||||
|
hashed_message = sha256(message.encode('utf-8')).hexdigest()
|
||||||
|
|
||||||
|
m = message + hashed_message
|
||||||
|
print('')
|
||||||
|
print('to be signed: ', m)
|
||||||
|
to_be_signed = binascii.hexlify(m.encode('utf-8'))
|
||||||
|
|
||||||
|
# Get the keys in their raw format
|
||||||
|
signing_key = ecdsa.SigningKey.generate()
|
||||||
|
public_key = signing_key.verifying_key
|
||||||
|
|
||||||
|
signature = signing_key.sign(to_be_signed)
|
||||||
|
signature_hex = signature.hex()
|
||||||
|
|
||||||
|
# deform_signature if deform argument is given
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
if sys.argv[1] == 'deform':
|
||||||
|
max_id = len(signature)
|
||||||
|
for i in range(max_id):
|
||||||
|
if i + 2 <= max_id:
|
||||||
|
mess_id = i + 2
|
||||||
|
mess = signature[mess_id].to_bytes(4, 'big')
|
||||||
|
replace_me = signature[i].to_bytes(4, 'big')
|
||||||
|
#print('>>> replacing ', replace_me, ' with ', mess )
|
||||||
|
print('>>> ', i, 'to', mess_id, ', max is: ', max_id)
|
||||||
|
signature = signature.replace(replace_me, mess )
|
||||||
|
|
||||||
|
print('signed: ', signature_hex)
|
||||||
|
print('')
|
||||||
|
|
||||||
|
try:
|
||||||
|
is_valid = public_key.verify(signature, to_be_signed)
|
||||||
|
except ecdsa.keys.BadSignatureError:
|
||||||
|
is_valid = False
|
||||||
|
print('Something bad is on foot')
|
||||||
|
|
||||||
|
if is_valid:
|
||||||
|
print('This is COOL')
|
||||||
|
else:
|
||||||
|
print('Something bad is on foot')
|
||||||
|
|
||||||
|
exit(0)
|
||||||
|
|
60
encryption-on-apis/flask-encrypted-api.py
Executable file
60
encryption-on-apis/flask-encrypted-api.py
Executable file
@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
from flask import Flask
|
||||||
|
from flask import request
|
||||||
|
import ecdsa
|
||||||
|
import codecs
|
||||||
|
|
||||||
|
ecdsa_public_key = '8716c78c09a4e4571a3112eca1c7ddce41289e20da446894b621f2a11ba91bc963f2e9fb9ddd5552c26faf814bc582b4'
|
||||||
|
#ecdsa_public_key = '048716c78c09a4e4571a3112eca1c7ddce41289e20da446894b621f2a11ba91bc963f2e9fb9ddd5552c26faf814bc582b4'
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route("/get/<id>", methods=['get'])
|
||||||
|
def get(id):
|
||||||
|
|
||||||
|
r_id = id
|
||||||
|
r_sum = request.args.get('sum')
|
||||||
|
r_auth = request.headers.get('auth')
|
||||||
|
|
||||||
|
|
||||||
|
print('---------------------------')
|
||||||
|
print('host: ', request.host)
|
||||||
|
print('full_path: ', request.full_path)
|
||||||
|
print('---------------------------')
|
||||||
|
print('id: ', r_id)
|
||||||
|
print('sum: ', r_sum)
|
||||||
|
print('header, auth:', r_auth)
|
||||||
|
|
||||||
|
signed_data = request.host + request.full_path
|
||||||
|
|
||||||
|
print('might have been signed: ', signed_data)
|
||||||
|
r_auth_bytes = bytes.fromhex(str(r_auth))
|
||||||
|
|
||||||
|
#x_coord = ecdsa_public_key[:64]
|
||||||
|
#y_coord = ecdsa_public_key[64:]
|
||||||
|
#
|
||||||
|
#if int(y_coord, 16) % 2 == 0:
|
||||||
|
# prefix = b'\x02'
|
||||||
|
#else:
|
||||||
|
# prefix = b'\x03'
|
||||||
|
#
|
||||||
|
#bytes_public_key = prefix + codecs.decode(x_coord, 'hex')
|
||||||
|
|
||||||
|
bytes_public_key = bytes.fromhex(ecdsa_public_key)
|
||||||
|
|
||||||
|
|
||||||
|
bytes_signed_data = signed_data.encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
vk = ecdsa.VerifyingKey.from_string(bytes_public_key, curve=ecdsa.SECP256k1)
|
||||||
|
|
||||||
|
if vk.verify(r_auth_bytes, bytes_signed_data):
|
||||||
|
response = "YES"
|
||||||
|
else:
|
||||||
|
response = "NO"
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
if __name__== "__main__":
|
||||||
|
app.run()
|
||||||
|
|
13
encryption-on-apis/gen-ecdsa-private-key-v2.py
Normal file
13
encryption-on-apis/gen-ecdsa-private-key-v2.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import ecdsa
|
||||||
|
|
||||||
|
sk = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
|
||||||
|
|
||||||
|
# Get the private key as a byte string
|
||||||
|
private_key_bytes = sk.to_string()
|
||||||
|
|
||||||
|
# Convert the private key byte string to a hexadecimal string
|
||||||
|
private_key_hex = private_key_bytes.hex()
|
||||||
|
|
||||||
|
print('private_key: ', private_key_hex)
|
15
encryption-on-apis/gen-ecdsa-private-key.py
Executable file
15
encryption-on-apis/gen-ecdsa-private-key.py
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import ecdsa
|
||||||
|
|
||||||
|
# Generate a new random private key
|
||||||
|
signing_key = ecdsa.SigningKey.generate()
|
||||||
|
|
||||||
|
# Get the private key as a byte string
|
||||||
|
private_key_bytes = signing_key.to_string()
|
||||||
|
|
||||||
|
# Convert the private key byte string to a hexadecimal string
|
||||||
|
private_key_hex = private_key_bytes.hex()
|
||||||
|
|
||||||
|
# Print the private key
|
||||||
|
print(private_key_hex)
|
20
encryption-on-apis/gen-private-key.py
Executable file
20
encryption-on-apis/gen-private-key.py
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import ec
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
|
||||||
|
|
||||||
|
def gen_key():
|
||||||
|
private_key = ec.generate_private_key(
|
||||||
|
ec.SECP256K1(), default_backend()
|
||||||
|
)
|
||||||
|
return private_key
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
key = gen_key()
|
||||||
|
hexkey = key.private_numbers().private_value.to_bytes(32, 'big').hex()
|
||||||
|
|
||||||
|
print(hexkey)
|
21
encryption-on-apis/gen-public-key.py
Executable file
21
encryption-on-apis/gen-public-key.py
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import ecdsa
|
||||||
|
|
||||||
|
# read in the first argument that should be ecdsa key in hex form
|
||||||
|
private_key_hex = sys.argv[1]
|
||||||
|
|
||||||
|
# Convert the private key from hexadecimal to an integer
|
||||||
|
private_key_int = int(private_key_hex, 16)
|
||||||
|
|
||||||
|
#print(private_key_int)
|
||||||
|
## Create a signing key object from the private key
|
||||||
|
signing_key = ecdsa.SigningKey.from_secret_exponent(private_key_int)
|
||||||
|
|
||||||
|
# Get the public key from the signing key object
|
||||||
|
public_key = signing_key.verifying_key
|
||||||
|
|
||||||
|
# Print the public key in hexadecimal format
|
||||||
|
##print(public_key.to_string("uncompressed").hex())
|
||||||
|
print(public_key.to_string("hybrid").hex())
|
33
encryption-on-apis/get-random-signed-string.py
Executable file
33
encryption-on-apis/get-random-signed-string.py
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
import ecdsa
|
||||||
|
import os, sys
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
|
||||||
|
# check if the private key was provided as a command-line argument
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Error: Private key not provided")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# generate a random byte string
|
||||||
|
random_bytes = os.urandom(32)
|
||||||
|
|
||||||
|
# compute the SHA-512 hash of the random bytes
|
||||||
|
#sha512 = hashlib.sha512(random_bytes).hexdigest()
|
||||||
|
sha512 = 'http://localhost:5000/get/1'
|
||||||
|
|
||||||
|
# read in the first argument that should be ecdsa key in hex form
|
||||||
|
private_key_hex = sys.argv[1]
|
||||||
|
|
||||||
|
# Convert the private key from hexadecimal to an integer
|
||||||
|
private_key_int = int(private_key_hex, 16)
|
||||||
|
|
||||||
|
# Generate SK from the private key
|
||||||
|
sk = ecdsa.SigningKey.from_secret_exponent(private_key_int, curve=ecdsa.SECP256k1)
|
||||||
|
|
||||||
|
# sign the message
|
||||||
|
signature = sk.sign(sha512.encode())
|
||||||
|
|
||||||
|
# print the signature
|
||||||
|
print(signature)
|
||||||
|
|
39
encryption-on-apis/singe-endpoint-api.py
Executable file
39
encryption-on-apis/singe-endpoint-api.py
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
## Single endpoint encrypted api
|
||||||
|
|
||||||
|
from flask import Flask
|
||||||
|
from flask import request
|
||||||
|
from hashlib import sha256
|
||||||
|
|
||||||
|
|
||||||
|
keys = {
|
||||||
|
'key1': 'user1',
|
||||||
|
'key2': 'user2'
|
||||||
|
}
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route("/<hex_hash>", methods=['post'])
|
||||||
|
def endpoint(hex_hash):
|
||||||
|
content_type = request.headers.get('content_type')
|
||||||
|
if content_type == 'application/json':
|
||||||
|
body = request.json
|
||||||
|
enc_data = body['foo']
|
||||||
|
|
||||||
|
## decrypt the enc_data
|
||||||
|
dec_data = enc_data
|
||||||
|
|
||||||
|
## Get checksum to compare against
|
||||||
|
dec_data_hash = sha256(dec_data.encode('utf-8')).hexdigest()
|
||||||
|
r_hash = hex_hash.encode('utf-8')
|
||||||
|
print('if', r_hash, '==', dec_data_hash)
|
||||||
|
|
||||||
|
response = "message: ", enc_data, "checksum: ", dec_data_hash
|
||||||
|
print(response)
|
||||||
|
return "YES"
|
||||||
|
else:
|
||||||
|
return 'Content-Type not supported'
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
91
encryption-on-apis/stackoverflow-example.py
Executable file
91
encryption-on-apis/stackoverflow-example.py
Executable file
@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import ecdsa
|
||||||
|
import binascii
|
||||||
|
import requests
|
||||||
|
from hashlib import sha256
|
||||||
|
from flask import Flask
|
||||||
|
from flask import request
|
||||||
|
|
||||||
|
|
||||||
|
##Generate them keys
|
||||||
|
# Generate private key (signing key)
|
||||||
|
sk = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
|
||||||
|
private_key_hex = sk.to_string().hex()
|
||||||
|
|
||||||
|
public_key = sk.verifying_key
|
||||||
|
public_key_hex = binascii.hexlify(public_key.to_string()).decode('utf-8')
|
||||||
|
|
||||||
|
keys = {
|
||||||
|
"private_key": private_key_hex,
|
||||||
|
"public_key": public_key_hex
|
||||||
|
}
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
line = '---------------------------------------'
|
||||||
|
|
||||||
|
@app.route('/send')
|
||||||
|
def send():
|
||||||
|
message = b"localhost:5000/get/123?sum=5f944f849124d36621d5f0708c7752a84fa9caa90bba629b8db93eea44cd0d1a"
|
||||||
|
|
||||||
|
print(line)
|
||||||
|
print('private_key: ', keys['private_key'])
|
||||||
|
print(line)
|
||||||
|
|
||||||
|
private_key_hex = keys['private_key']
|
||||||
|
private_key = ecdsa.SigningKey.from_string(bytes.fromhex(private_key_hex), curve=ecdsa.SECP256k1)
|
||||||
|
|
||||||
|
sig_hex = binascii.hexlify(private_key.sign(message)).decode('utf-8')
|
||||||
|
#print('sig:', sig_hex)
|
||||||
|
|
||||||
|
reply = requests.get('http://localhost:5000/get/123', headers={"auth": sig_hex})
|
||||||
|
|
||||||
|
output_status = str(reply.status_code)
|
||||||
|
output_content = str(reply.content)
|
||||||
|
|
||||||
|
return output_content, output_status
|
||||||
|
|
||||||
|
@app.route('/get/<c_id>')
|
||||||
|
def get(c_id):
|
||||||
|
#vk = sk.get_verifying_key()
|
||||||
|
# Get the public key from the signing key object
|
||||||
|
public_key = keys['public_key']
|
||||||
|
print("public_key:", public_key)
|
||||||
|
print(line)
|
||||||
|
print("got id: ", c_id)
|
||||||
|
|
||||||
|
# Get the sig from auth header
|
||||||
|
sig = request.headers.get('auth')
|
||||||
|
#print("vk2 - sig: ", sig)
|
||||||
|
|
||||||
|
# Get sig to bytes format, from str
|
||||||
|
sig_bytes = bytes.fromhex(sig)
|
||||||
|
|
||||||
|
## BUILD THE "message"
|
||||||
|
message = b"localhost:5000/get/123?sum=5f944f849124d36621d5f0708c7752a84fa9caa90bba629b8db93eea44cd0d1a"
|
||||||
|
|
||||||
|
vk = ecdsa.VerifyingKey.from_string(bytes.fromhex(public_key_hex), curve=ecdsa.SECP256k1)
|
||||||
|
|
||||||
|
reply = '{'
|
||||||
|
if vk.verify(sig_bytes, message):
|
||||||
|
# print('vk1 # True ')
|
||||||
|
reply = reply + 'vk1: OK'
|
||||||
|
else:
|
||||||
|
# print('vk1 # False ')
|
||||||
|
reply = reply + 'vk1: ERROR'
|
||||||
|
|
||||||
|
|
||||||
|
vk2 = ecdsa.VerifyingKey.from_string(bytes.fromhex(public_key_hex), curve=ecdsa.SECP256k1) # the default is sha1
|
||||||
|
if vk2.verify(sig_bytes, message):
|
||||||
|
# print('vk2 # True ')
|
||||||
|
reply = reply + ', vk2: OK'
|
||||||
|
else:
|
||||||
|
# print('vk2 # False ')
|
||||||
|
reply = reply + ', vk2: ERROR'
|
||||||
|
|
||||||
|
reply = reply + '}'
|
||||||
|
#print(reply)
|
||||||
|
return reply
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
25
encryption-on-apis/verify.py
Executable file
25
encryption-on-apis/verify.py
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import ecdsa
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# read the original message from the first command-line argument
|
||||||
|
message = sys.argv[1]
|
||||||
|
|
||||||
|
# read the signature from standard input
|
||||||
|
signature = sys.stdin.read()
|
||||||
|
|
||||||
|
# read the public key from the second command-line argument
|
||||||
|
public_key = sys.argv[2]
|
||||||
|
|
||||||
|
print('message: ', message)
|
||||||
|
print('signature: ', signature)
|
||||||
|
print('public key: ', public_key)
|
||||||
|
|
||||||
|
|
||||||
|
# generate a verifying key from the public key
|
||||||
|
vk = ecdsa.VerifyingKey.from_string(public_key, curve=ecdsa.SECP256k1)
|
||||||
|
|
||||||
|
# verify the signature
|
||||||
|
#assert vk.verify(signature, message.encode())
|
||||||
|
|
15
graph-scatter.py
Normal file
15
graph-scatter.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
# Create some sample data
|
||||||
|
x = [1, 2, 3, 4, 5]
|
||||||
|
y = [2, 4, 6, 8, 10]
|
||||||
|
|
||||||
|
# Plot the data as points
|
||||||
|
plt.scatter(x, y)
|
||||||
|
|
||||||
|
# Add labels to the axes
|
||||||
|
plt.xlabel('Time')
|
||||||
|
plt.ylabel('Value')
|
||||||
|
|
||||||
|
# Show the plot
|
||||||
|
plt.show()
|
49
letter-to-GPT.memo
Normal file
49
letter-to-GPT.memo
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
I would like to have a program that contors to these rules:
|
||||||
|
|
||||||
|
1. written in python3
|
||||||
|
2. singe file
|
||||||
|
|
||||||
|
And then makes these things:
|
||||||
|
|
||||||
|
1. record the bitcoin price
|
||||||
|
|
||||||
|
1.1. by fetching:
|
||||||
|
source = 'http://api.binance.com/api/v3/avgPrice'
|
||||||
|
payload = {'symbol': 'BTCUSDT'}
|
||||||
|
response = requests.get(source, params=payload)
|
||||||
|
|
||||||
|
binance api response is like:
|
||||||
|
{
|
||||||
|
"mins": 5,
|
||||||
|
"price: "170.20"
|
||||||
|
}
|
||||||
|
|
||||||
|
1.2. and storing it in sqlite3 or other embedded database
|
||||||
|
The database should hold these informations:
|
||||||
|
* timestamp as unix timestamp
|
||||||
|
* value of the symbol
|
||||||
|
* name of the symbol
|
||||||
|
* source of the symbol
|
||||||
|
|
||||||
|
1.3
|
||||||
|
Fetch the price every "mins" minutes, something like:
|
||||||
|
time_delta = time.now() - timestamp_of_last_record
|
||||||
|
if time_delta <= mins_from_last_record
|
||||||
|
fetch_new_price_data()
|
||||||
|
|
||||||
|
2. serve a http/json api to send the gathered price data forward
|
||||||
|
|
||||||
|
Every response from this api should contain sha256 checksum as last element it is json document.
|
||||||
|
This api should be accessible by token authentication.
|
||||||
|
|
||||||
|
2.1 allow full dump of the database as json document
|
||||||
|
|
||||||
|
2.2 allow partial dump by getting limiting timestamp as of attribure from the http get reqeust
|
||||||
|
|
||||||
|
3. Hold the sice of the files under control
|
||||||
|
|
||||||
|
The database that holds the price data should be rotated every midnight.
|
||||||
|
So that we dont end up with large database files on the server.
|
||||||
|
|
||||||
|
Can you generate this?
|
||||||
|
I think to make this work there needs to be threading. One thread for the data gathering and another for the api serving.
|
62
letters/Flask_and_backend_process.py
Normal file
62
letters/Flask_and_backend_process.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
from flask import Flask
|
||||||
|
import threading
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
# Create a lock for synchronizing access to the database
|
||||||
|
lock = threading.Lock()
|
||||||
|
|
||||||
|
def my_background_process():
|
||||||
|
# Acquire the lock
|
||||||
|
lock.acquire()
|
||||||
|
|
||||||
|
# Connect to the in-memory database
|
||||||
|
conn = sqlite3.connect(':memory:')
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# Create a table in the database
|
||||||
|
c.execute("CREATE TABLE mytable (col1 INTEGER, col2 TEXT)")
|
||||||
|
|
||||||
|
# Write to the database
|
||||||
|
c.execute("INSERT INTO mytable (col1, col2) VALUES (?, ?)", (value1, value2))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# Close the connection
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# Release the lock
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def read_from_database():
|
||||||
|
# Acquire the lock
|
||||||
|
lock.acquire()
|
||||||
|
|
||||||
|
# Connect to the in-memory database
|
||||||
|
conn = sqlite3.connect(':memory:')
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# Read from the database
|
||||||
|
c.execute("SELECT * FROM mytable")
|
||||||
|
rows = c.fetchall()
|
||||||
|
|
||||||
|
# Close the connection
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# Release the lock
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
# Return the rows to the client
|
||||||
|
return rows
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Create a new thread for the background process
|
||||||
|
thread = threading.Thread(target=my_background_process)
|
||||||
|
|
||||||
|
# Start the thread
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
# Start the Flask app
|
||||||
|
app.run()
|
||||||
|
|
@ -0,0 +1,87 @@
|
|||||||
|
- how to send and receive encrypted http post body in python?
|
||||||
|
|
||||||
|
To send and receive encrypted HTTP POST body data in Python, you can use the cryptography package to encrypt the data before sending it and to decrypt the data after receiving it. Here is an example of how this can be done:
|
||||||
|
|
||||||
|
# Import the necessary modules
|
||||||
|
from cryptography.fernet import Fernet
|
||||||
|
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
||||||
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
import base64
|
||||||
|
import requests
|
||||||
|
|
||||||
|
# Generate a secure key using PBKDF2
|
||||||
|
password = "my_secret_password"
|
||||||
|
salt = b"my_secret_salt"
|
||||||
|
kdf = PBKDF2HMAC(
|
||||||
|
algorithm=hashes.SHA256(),
|
||||||
|
length=32,
|
||||||
|
salt=salt,
|
||||||
|
iterations=100000
|
||||||
|
)
|
||||||
|
key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
|
||||||
|
|
||||||
|
# Initialize Fernet
|
||||||
|
fernet = Fernet(key)
|
||||||
|
|
||||||
|
# Define the URL and the data to be sent
|
||||||
|
url = "https://www.example.com/post"
|
||||||
|
data = {
|
||||||
|
"username": "my_username",
|
||||||
|
"password": "my_password"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Encrypt the data
|
||||||
|
encrypted_data = fernet.encrypt(str(data).encode())
|
||||||
|
|
||||||
|
# Send the encrypted data as the POST body
|
||||||
|
response = requests.post(url, data=encrypted_data)
|
||||||
|
|
||||||
|
# Decrypt the response data
|
||||||
|
decrypted_data = fernet.decrypt(response.content)
|
||||||
|
|
||||||
|
# Print the decrypted data
|
||||||
|
print(decrypted_data)
|
||||||
|
|
||||||
|
In this example, we first use the PBKDF2HMAC class from the cryptography package to generate a secure key that we will use to encrypt and decrypt the data. Then, we initialize a Fernet object with this key, and we define the URL and the data that we want to send as an encrypted HTTP POST request.
|
||||||
|
|
||||||
|
Next, we use the encrypt() method of the Fernet object to encrypt the data, and we use the requests library to send the encrypted data as the POST body to the specified URL.
|
||||||
|
|
||||||
|
Finally, we use the decrypt() method of the Fernet object to decrypt the response data, and we print it to verify that it matches the original data.
|
||||||
|
|
||||||
|
This is just one way to send and receive encrypted HTTP POST body data in Python. There are many other encryption algorithms and libraries that you can use to achieve the same result.
|
||||||
|
|
||||||
|
|
||||||
|
- What is this Fernet?
|
||||||
|
|
||||||
|
Fernet is a symmetric encryption algorithm that is part of the cryptography package in Python. It uses a secure key to encrypt and decrypt data, and it guarantees that the encrypted data cannot be altered or read without the key.
|
||||||
|
|
||||||
|
Fernet is based on the Advanced Encryption Standard (AES) algorithm and uses a combination of symmetric encryption, a message authentication code (MAC), and a secure key derivation function (KDF) to provide strong encryption and integrity protection. It is considered to be very secure when used properly.
|
||||||
|
|
||||||
|
In Python, Fernet is easy to use and can be integrated into a wide variety of applications that need to securely encrypt and decrypt data. Here is a simple example of how to use Fernet in Python:
|
||||||
|
|
||||||
|
from cryptography.fernet import Fernet
|
||||||
|
|
||||||
|
# Generate a secure key
|
||||||
|
key = Fernet.generate_key()
|
||||||
|
|
||||||
|
# Initialize Fernet with the key
|
||||||
|
fernet = Fernet(key)
|
||||||
|
|
||||||
|
# Define the data that we want to encrypt
|
||||||
|
data = "my_secret_message"
|
||||||
|
|
||||||
|
# Encrypt the data
|
||||||
|
encrypted_data = fernet.encrypt(data.encode())
|
||||||
|
|
||||||
|
# Decrypt the data
|
||||||
|
decrypted_data = fernet.decrypt(encrypted_data)
|
||||||
|
|
||||||
|
# Print the decrypted data to verify that it matches the original data
|
||||||
|
print(decrypted_data.decode())
|
||||||
|
|
||||||
|
|
||||||
|
In this example, we first generate a secure key using the generate_key() method of the Fernet class. Then, we initialize a Fernet object with this key, and we define the data that we want to encrypt.
|
||||||
|
|
||||||
|
Next, we use the encrypt() method of the Fernet object to encrypt the data, and we use the decrypt() method to decrypt the encrypted data. Finally, we print the decrypted data to verify that it matches the original data.
|
||||||
|
|
||||||
|
This is just a simple example of how Fernet can be used in Python. In practice, you would need to securely store and manage the key, and you may want to use other methods or options provided by the cryptography package to customize the encryption and decryption process.
|
21
letters/openGPT-btc-price-fetch.py
Normal file
21
letters/openGPT-btc-price-fetch.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import requests
|
||||||
|
|
||||||
|
def fetch_price_data():
|
||||||
|
# Set up the URL and payload for the API request
|
||||||
|
source = 'http://api.binance.com/api/v3/avgPrice'
|
||||||
|
payload = {'symbol': 'BTCUSDT'}
|
||||||
|
|
||||||
|
# Send the API request and parse the response
|
||||||
|
response = requests.get(source, params=payload)
|
||||||
|
data = response.json()
|
||||||
|
mins = data['mins']
|
||||||
|
price = data['price']
|
||||||
|
|
||||||
|
# Store the data in the SQLite database
|
||||||
|
conn = sqlite3.connect('database.db')
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute('INSERT INTO price_data (timestamp, value, symbol, source) VALUES (?, ?, ?, ?)', (time.time(), price, 'BTCUSDT', 'Binance'))
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return mins
|
19
letters/openGPT-example-on-thread-locks.py
Normal file
19
letters/openGPT-example-on-thread-locks.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import threading
|
||||||
|
|
||||||
|
# Create a thread lock for the database
|
||||||
|
database_lock = threading.Lock()
|
||||||
|
|
||||||
|
def write_to_database(data):
|
||||||
|
# Acquire the thread lock before accessing the database
|
||||||
|
with database_lock:
|
||||||
|
# Write data to the database
|
||||||
|
# (database logic goes here)
|
||||||
|
print('Wrote to the database')
|
||||||
|
|
||||||
|
def rotate_database():
|
||||||
|
# Acquire the thread lock before rotating the database
|
||||||
|
with database_lock:
|
||||||
|
# Rotate the database
|
||||||
|
# (database rotation logic goes here)
|
||||||
|
print('Rotated the database')
|
||||||
|
|
37
letters/openGPT-flask-api.py
Normal file
37
letters/openGPT-flask-api.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
from flask import Flask, request
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
# Create a Flask app and set up the API endpoint
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route('/dump_db', methods=['GET'])
|
||||||
|
def dump_db():
|
||||||
|
# Connect to the SQLite database
|
||||||
|
conn = sqlite3.connect('database.db')
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# Retrieve the data from the database
|
||||||
|
cursor.execute('SELECT * FROM price_data')
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
|
# Format the data as a JSON document
|
||||||
|
data = {
|
||||||
|
'timestamp': [row[0] for row in rows],
|
||||||
|
'value': [row[1] for row in rows],
|
||||||
|
'symbol': [row[2] for row in rows],
|
||||||
|
'source': [row[3] for row in rows],
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if a timestamp was provided in the request
|
||||||
|
timestamp = request.args.get('timestamp')
|
||||||
|
if timestamp:
|
||||||
|
# Filter the data to only include rows with a timestamp greater than or equal to the provided value
|
||||||
|
data = {k: [v for i, v in enumerate(v) if data['timestamp'][i] >= timestamp] for k, v in data.items()}
|
||||||
|
|
||||||
|
# Return the data as a JSON response
|
||||||
|
return data
|
||||||
|
|
||||||
|
# Run the app
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run()
|
||||||
|
|
22
letters/openGPT-python-threads.py
Normal file
22
letters/openGPT-python-threads.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
from threading import Thread
|
||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route('/api')
|
||||||
|
def api():
|
||||||
|
# API logic here
|
||||||
|
return 'API response'
|
||||||
|
|
||||||
|
def data_request_task():
|
||||||
|
# Data requesting logic here
|
||||||
|
print('Data request task finished')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Start the Flask API in a separate thread
|
||||||
|
api_thread = Thread(target=app.run)
|
||||||
|
api_thread.start()
|
||||||
|
|
||||||
|
# Run the data requesting task
|
||||||
|
data_request_task()
|
||||||
|
|
49
letters/python-by-chatGPT.py
Normal file
49
letters/python-by-chatGPT.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import http.server
|
||||||
|
import json
|
||||||
|
|
||||||
|
from ecdsa import VerifyingKey, NIST384p
|
||||||
|
|
||||||
|
user_and_tokens = {
|
||||||
|
"user1": ecdsa_public_key_from_user1
|
||||||
|
}
|
||||||
|
|
||||||
|
class RequestHandler(http.server.BaseHTTPRequestHandler):
|
||||||
|
|
||||||
|
def do_POST(self):
|
||||||
|
if self.path == '/auth':
|
||||||
|
content_length = int(self.headers['Content-Length'])
|
||||||
|
request_data = json.loads(self.rfile.read(content_length))
|
||||||
|
|
||||||
|
# Check the JSON post data for the required fields
|
||||||
|
if 'person' not in request_data or 'signature' not in request_data:
|
||||||
|
self.send_response(400)
|
||||||
|
self.end_headers()
|
||||||
|
return
|
||||||
|
|
||||||
|
person = request_data['person']
|
||||||
|
signature = request_data['signature']
|
||||||
|
|
||||||
|
# Check the person data for the required fields
|
||||||
|
if 'user' not in person or 'token' not in person:
|
||||||
|
self.send_response(400)
|
||||||
|
self.end_headers()
|
||||||
|
return
|
||||||
|
|
||||||
|
user = person['user']
|
||||||
|
token = person['token']
|
||||||
|
|
||||||
|
# Check the signature data for the required fields
|
||||||
|
if 'signature' not in signature or 'curve' not in signature:
|
||||||
|
self.send_response(400)
|
||||||
|
self.end_headers()
|
||||||
|
return
|
||||||
|
|
||||||
|
sig = signature['signature']
|
||||||
|
curve = signature['curve']
|
||||||
|
|
||||||
|
# Verify the signature using the provided public key
|
||||||
|
vk = VerifyingKey.from_string(pre_delivered_public_key, curve=getattr(NIST384p, curve))
|
||||||
|
if vk.verify(sig, user + token):
|
||||||
|
print("allow")
|
||||||
|
self.send_response(200)
|
||||||
|
|
15
letters/response-1.memo
Normal file
15
letters/response-1.memo
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Yes, it is possible to create a program in Python that satisfies the requirements you have outlined. Here is a rough outline of how such a program might work:
|
||||||
|
|
||||||
|
The program will be written in Python 3 and be contained in a single file.
|
||||||
|
|
||||||
|
To record the Bitcoin price, the program will use the requests module to fetch the price data from the Binance API. The response from the API will be parsed to extract the mins and price values, which will be stored in an SQLite database along with the current timestamp, the symbol name, and the source of the data.
|
||||||
|
|
||||||
|
To ensure that the program fetches the price data at regular intervals, it will use a timer to check the time since the last data was fetched. If the time since the last fetch is greater than the mins value from the API response, the program will fetch new data.
|
||||||
|
|
||||||
|
To serve the price data via an HTTP/JSON API, the program will use the flask module to create a server that listens for incoming HTTP requests. The server will be configured to require token authentication, and will provide two endpoints: one for dumping the entire database as a JSON document, and another for dumping a subset of the data based on a provided timestamp.
|
||||||
|
|
||||||
|
To control the size of the database, the program will use a daily timer to rotate the database at midnight each day. This will involve creating a new database file and copying the data from the old database into the new one, then deleting the old database file.
|
||||||
|
|
||||||
|
To implement the program, you will need to use Python's threading module to create separate threads for the data gathering and API serving processes. This will allow the program to fetch data and serve requests concurrently, ensuring that the API is always available and up-to-date.
|
||||||
|
|
||||||
|
I hope this helps! Let me know if you have any other questions.
|
27
pseudo-code
Normal file
27
pseudo-code
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
my-web-auth-part.code
|
||||||
|
|
||||||
|
open http listerner
|
||||||
|
|
||||||
|
pre_delivered_public_key = 123456789
|
||||||
|
|
||||||
|
if reguest get to /auth
|
||||||
|
check for json post data
|
||||||
|
post data:
|
||||||
|
{
|
||||||
|
person: {
|
||||||
|
user: username
|
||||||
|
token: token
|
||||||
|
},
|
||||||
|
signature: {
|
||||||
|
signature: ecdsa_signature
|
||||||
|
curve: curve
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ecdsa.verify( username+token, pre_delivered_public_key )
|
||||||
|
then
|
||||||
|
print "allow"
|
||||||
|
return "{ status: success }"
|
||||||
|
else
|
||||||
|
print "deny from: ", user
|
||||||
|
return "{ status: ", failure }"
|
21
python-check-point.py
Normal file
21
python-check-point.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# Create some sample data
|
||||||
|
x = [1, 5]
|
||||||
|
y = [2, 10]
|
||||||
|
|
||||||
|
# Fit a line to the data using numpy
|
||||||
|
coefficients = np.polyfit(x, y, 1)
|
||||||
|
line = np.poly1d(coefficients)
|
||||||
|
|
||||||
|
# Check if the point (3, 6) is above or below the line
|
||||||
|
point = (3, 2)
|
||||||
|
if point[1] > line(point[0]):
|
||||||
|
print('The point is above the line.')
|
||||||
|
else:
|
||||||
|
print('The point is below the line.')
|
||||||
|
|
||||||
|
plt.plot(x, y)
|
||||||
|
plt.scatter(point[0], point[1], color='r')
|
||||||
|
plt.show()
|
19
python-graph.py
Normal file
19
python-graph.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
# Create some sample data
|
||||||
|
x = [1, 5]
|
||||||
|
y = [2, 10]
|
||||||
|
|
||||||
|
# Plot the data
|
||||||
|
plt.plot(x, y)
|
||||||
|
|
||||||
|
# Add a point to the plot
|
||||||
|
plt.scatter([2], [6], color='r')
|
||||||
|
|
||||||
|
# Add labels to the axes
|
||||||
|
plt.xlabel('Time')
|
||||||
|
plt.ylabel('Value')
|
||||||
|
|
||||||
|
# Show the plot
|
||||||
|
plt.show()
|
||||||
|
|
30
shared-secret/chatgpt-example.py
Executable file
30
shared-secret/chatgpt-example.py
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
from secretsharing import PlaintextToHexSecretSharer
|
||||||
|
|
||||||
|
# The secret that we want to split
|
||||||
|
secret = "my_secret_password"
|
||||||
|
|
||||||
|
# The number of shares that we want to generate
|
||||||
|
n_shares = 5
|
||||||
|
|
||||||
|
# The threshold (i.e., the minimum number of shares required to reconstruct the secret)
|
||||||
|
threshold = 3
|
||||||
|
|
||||||
|
# Generate the shares
|
||||||
|
shares = PlaintextToHexSecretSharer.split_secret(secret, n_shares, threshold)
|
||||||
|
|
||||||
|
# Print the shares
|
||||||
|
for share in shares:
|
||||||
|
print(share)
|
||||||
|
|
||||||
|
# To reconstruct the secret, we need at least the threshold number of shares
|
||||||
|
# Let's say we have these three shares:
|
||||||
|
shares_to_reconstruct = [shares[0], shares[2], shares[4]]
|
||||||
|
|
||||||
|
# Reconstruct the secret
|
||||||
|
secret = PlaintextToHexSecretSharer.recover_secret(shares_to_reconstruct)
|
||||||
|
|
||||||
|
# Print the secret
|
||||||
|
print(secret)
|
||||||
|
|
1
test.price.json
Normal file
1
test.price.json
Normal file
File diff suppressed because one or more lines are too long
59
testing.py
Normal file
59
testing.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import ecdsa
|
||||||
|
import binascii
|
||||||
|
import requests
|
||||||
|
from hashlib import sha256
|
||||||
|
from flask import Flask
|
||||||
|
from flask import request
|
||||||
|
|
||||||
|
|
||||||
|
##Generate them keys
|
||||||
|
# Generate private key (signing key)
|
||||||
|
sk = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
|
||||||
|
private_key_hex = sk.to_string().hex()
|
||||||
|
|
||||||
|
public_key = sk.verifying_key
|
||||||
|
public_key_hex = binascii.hexlify(public_key.to_string()).decode('utf-8')
|
||||||
|
|
||||||
|
keys = {
|
||||||
|
"private_key": private_key_hex,
|
||||||
|
"public_key": public_key_hex
|
||||||
|
}
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route('/send')
|
||||||
|
def send():
|
||||||
|
message = b"localhost:5000/get/123?sum=5f944f849124d36621d5f0708c7752a84fa9caa90bba629b8db93eea44cd0d1a"
|
||||||
|
|
||||||
|
print('private_key: ', private_key_hex)
|
||||||
|
sig = sk.sign(message)
|
||||||
|
|
||||||
|
|
||||||
|
reply = requests.get('http://localhost:5000/get/', headers={"auth": sig})
|
||||||
|
return reply.str()
|
||||||
|
|
||||||
|
@app.route('/get')
|
||||||
|
def get():
|
||||||
|
#vk = sk.get_verifying_key()
|
||||||
|
# Get the public key from the signing key object
|
||||||
|
print("vk2 - public_key:", keys['public_key'])
|
||||||
|
|
||||||
|
# Get the sig from auth header
|
||||||
|
sig = request.headers.get('auth')
|
||||||
|
|
||||||
|
vk = ecdsa.VerifyingKey.from_string(bytes.fromhex(public_key_hex), curve=ecdsa.SECP256k1)
|
||||||
|
print('sig: ', binascii.hexlify(sig).decode('utf-8'))
|
||||||
|
if vk.verify(sig, message):
|
||||||
|
print('vk1 # True ')
|
||||||
|
else:
|
||||||
|
print('vk1 # False ')
|
||||||
|
|
||||||
|
|
||||||
|
vk2 = ecdsa.VerifyingKey.from_string(bytes.fromhex(public_key_hex), curve=ecdsa.SECP256k1) # the default is sha1
|
||||||
|
if vk2.verify(sig, message):
|
||||||
|
print('vk2 # True ')
|
||||||
|
else:
|
||||||
|
print('vk2 # False ')
|
||||||
|
|
0
timeseries.db
Normal file
0
timeseries.db
Normal file
37
webapp/celery-test.py
Executable file
37
webapp/celery-test.py
Executable file
@ -0,0 +1,37 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
from celery import Celery
|
||||||
|
from celery.backends import sqlalchemy
|
||||||
|
from flask import Flask
|
||||||
|
import requests
|
||||||
|
|
||||||
|
# create Flask app
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
# create a Celery app
|
||||||
|
celery_app = Celery('tasks')
|
||||||
|
|
||||||
|
# configure the app to use the sqlalchemy backend and specify the SQLite database URL as the broker
|
||||||
|
app.conf.update(
|
||||||
|
result_backend='sqlalchemy',
|
||||||
|
broker_url='sqlite:///celery.db',
|
||||||
|
task_serializer='json',
|
||||||
|
result_serializer='json',
|
||||||
|
)
|
||||||
|
|
||||||
|
@celery_app.task
|
||||||
|
def get_public_ip():
|
||||||
|
response = requests.get('https://ifconfig.me/ip')
|
||||||
|
return response.text
|
||||||
|
|
||||||
|
# define a Flask route that returns the current public IP address
|
||||||
|
@app.route('/public_ip')
|
||||||
|
def public_ip():
|
||||||
|
# call the get_public_ip task and wait for it to complete
|
||||||
|
result = get_public_ip.delay().get()
|
||||||
|
|
||||||
|
# return the task result as the response
|
||||||
|
return result
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run()
|
70
webapp/flask-dump.py
Executable file
70
webapp/flask-dump.py
Executable file
@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
import json
|
||||||
|
import sqlite3
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
# Initialize the Flask app
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
# Dump the contents of a SQLite database to the response
|
||||||
|
@app.route("/dump/<ask_timestamp>")
|
||||||
|
def dump(ask_timestamp):
|
||||||
|
# Open the database connection
|
||||||
|
con = sqlite3.connect("../btc_timeseries.db")
|
||||||
|
|
||||||
|
|
||||||
|
# Create a cursor to navigate the database
|
||||||
|
cur = con.cursor()
|
||||||
|
|
||||||
|
# Fetch all rows from the table
|
||||||
|
rows = cur.execute("SELECT * FROM timeseries").fetchall()
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"parameter": ask_timestamp,
|
||||||
|
"rows": rows
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build the response as a string
|
||||||
|
response = json.dumps(data)
|
||||||
|
|
||||||
|
con.close()
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
old_timestamp = time.strptime(row[0], "%Y-%m-%d %H:%M:%S")
|
||||||
|
unix_timestamp = time.mktime(old_timestamp)
|
||||||
|
if int(ask_timestamp) < int(unix_timestamp):
|
||||||
|
print('EQUALS: ', ask_timestamp, ' AND ', unix_timestamp)
|
||||||
|
else:
|
||||||
|
print('NOPE ', row[0], ' AS ', unix_timestamp)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
#@app.route("/dump/timestamp")
|
||||||
|
#def dump(timestamp):
|
||||||
|
# # Open the database connection
|
||||||
|
# con = sqlite3.connect("../btc_timeseries.db")
|
||||||
|
#
|
||||||
|
# print(timestamp)
|
||||||
|
#
|
||||||
|
# # Create a cursor to navigate the database
|
||||||
|
# cur = con.cursor()
|
||||||
|
#
|
||||||
|
# # Fetch all rows from the table
|
||||||
|
# rows = cur.execute("SELECT * FROM timeseries").fetchall()
|
||||||
|
#
|
||||||
|
# # Build the response as a string
|
||||||
|
# response = ""
|
||||||
|
# for row in rows:
|
||||||
|
# response += ", ".join(row) + "\n"
|
||||||
|
#
|
||||||
|
# # Close the database connection
|
||||||
|
# con.close()
|
||||||
|
#
|
||||||
|
# # Return the response
|
||||||
|
# return response
|
||||||
|
|
||||||
|
# Run the app
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
65
webapp/test.py
Executable file
65
webapp/test.py
Executable file
@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
from celery import Celery
|
||||||
|
from celery.backends import sqlalchemy
|
||||||
|
from datetime import datetime
|
||||||
|
from flask import Flask
|
||||||
|
import requests
|
||||||
|
from sqlalchemy import create_engine, Column, Integer, String, DateTime
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
|
||||||
|
# create a Flask app
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
# create a Celery app and configure it to use the sqlalchemy backend and the SQLite database specified by the broker_url
|
||||||
|
celery_app = Celery('tasks')
|
||||||
|
celery_app.conf.update(
|
||||||
|
result_backend='sqlalchemy',
|
||||||
|
broker_url='sqlite:///celery.db',
|
||||||
|
task_serializer='json',
|
||||||
|
result_serializer='json',
|
||||||
|
)
|
||||||
|
|
||||||
|
# define the get_public_ip Celery task (as in the previous example)
|
||||||
|
@celery_app.task
|
||||||
|
def get_public_ip():
|
||||||
|
response = requests.get('https://ifconfig.me/ip')
|
||||||
|
return response.text
|
||||||
|
|
||||||
|
# create an SQLAlchemy base class
|
||||||
|
Base = declarative_base()
|
||||||
|
|
||||||
|
# define an IPHistory model that will be used to store IP addresses and timestamps in the database
|
||||||
|
class IPHistory(Base):
|
||||||
|
__tablename__ = 'ip_history'
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
ip_address = Column(String)
|
||||||
|
timestamp = Column(DateTime, default=datetime.now)
|
||||||
|
|
||||||
|
# create a database engine and connect to the ip_history.db database
|
||||||
|
engine = create_engine('sqlite:///ip_history.db')
|
||||||
|
Base.metadata.create_all(engine)
|
||||||
|
|
||||||
|
# create a session object that will be used to add records to the database
|
||||||
|
Session = sessionmaker(bind=engine)
|
||||||
|
session = Session()
|
||||||
|
|
||||||
|
# define a Flask route that returns the current public IP address
|
||||||
|
@app.route('/public_ip')
|
||||||
|
def public_ip():
|
||||||
|
# call the get_public_ip task and wait for it to complete
|
||||||
|
ip_address = get_public_ip.delay().get()
|
||||||
|
|
||||||
|
# create a new IPHistory record and add it to the database
|
||||||
|
record = IPHistory(ip_address=ip_address)
|
||||||
|
session.add(record)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
# return the current IP address as the response
|
||||||
|
return ip_address
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user