Merge branch 'main' of gitlab.com:bashrc2/epicyon

merge-requests/30/head
Bob Mottram 2021-11-23 15:10:22 +00:00
commit 5954306e43
5 changed files with 141 additions and 126 deletions

View File

@ -352,51 +352,32 @@ echo "Creating nginx virtual host for http://${I2P_DOMAIN}"
echo ' error_log /dev/null;';
echo '';
echo ' index index.html;';
echo '';
echo ' location /newsmirror {';
echo " root /var/www/${I2P_DOMAIN}/htdocs;";
echo ' try_files $uri =404;';
echo ' }';
echo '';
echo ' location / {';
echo ' proxy_http_version 1.1;';
echo ' client_max_body_size 31M;';
echo " proxy_hide_header Upgrade;";
echo ' proxy_hide_header Connection;';
echo " proxy_set_header Host \$http_host;";
echo " proxy_set_header X-Real-IP \$remote_addr;";
echo " proxy_set_header X-Forward-For \$proxy_add_x_forwarded_for;";
echo ' proxy_set_header X-Forward-Proto http;';
echo ' proxy_set_header X-Nginx-Proxy true;';
echo ' proxy_set_header Upgrade-Insecure-Requests false;';
echo ' expires epoch;';
echo ' proxy_no_cache 1;';
echo ' proxy_temp_file_write_size 64k;';
echo ' proxy_connect_timeout 10080s;';
echo ' proxy_send_timeout 10080;';
echo ' proxy_read_timeout 10080;';
echo ' proxy_buffer_size 64k;';
echo ' proxy_buffers 16 32k;';
echo ' proxy_busy_buffers_size 64k;';
echo ' proxy_redirect off;';
echo ' proxy_request_buffering off;';
echo ' proxy_buffering on;';
echo ' proxy_cache my_cache;';
echo ' proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;';
echo " location ~ ^/(icons|images|media|emoji)/(.*)/(.*).(png|jpg|gif|webp|mp3|ogv|ogg|mp4) {";
echo ' expires 7d;';
echo " proxy_pass http://localhost:${EPICYON_PORT};";
echo ' }';
echo " location ~ ^/icons/(.*)/(like|repeat|calendar)(.*).(png|jpg|gif|webp|mp3|ogv|ogg|mp4) {";
echo ' expires epoch;';
echo ' proxy_no_cache 1;';
echo " proxy_pass http://localhost:${EPICYON_PORT};";
echo ' }';
echo " location ~ ^/icons/(like|repeat|calendar)(.*).(png|jpg|gif|webp|mp3|ogv|ogg|mp4) {";
echo ' expires epoch;';
echo ' proxy_no_cache 1;';
echo " proxy_pass http://localhost:${EPICYON_PORT};";
echo ' }';
echo " location ~ ^/users/(.*)/(image|banner).(png|jpg|gif|webp|mp3|ogv|ogg|mp4) {";
echo ' expires epoch;';
echo ' proxy_no_cache 1;';
echo " proxy_pass http://localhost:${EPICYON_PORT};";
echo ' }';
echo " proxy_pass http://localhost:${EPICYON_PORT};";
echo ' proxy_http_version 1.1;';
echo ' client_max_body_size 31M;';
echo " proxy_set_header Host \$http_host;";
echo " proxy_set_header X-Real-IP \$remote_addr;";
echo " proxy_set_header X-Forward-For \$proxy_add_x_forwarded_for;";
echo ' proxy_set_header X-Forward-Proto http;';
echo ' proxy_set_header X-Nginx-Proxy true;';
echo ' proxy_temp_file_write_size 64k;';
echo ' proxy_connect_timeout 10080s;';
echo ' proxy_send_timeout 10080;';
echo ' proxy_read_timeout 10080;';
echo ' proxy_buffer_size 64k;';
echo ' proxy_buffers 16 32k;';
echo ' proxy_busy_buffers_size 64k;';
echo ' proxy_redirect off;';
echo ' proxy_request_buffering off;';
echo ' proxy_buffering off;';
echo " proxy_pass http://localhost:${EPICYON_PORT};";
echo ' tcp_nodelay on;';
echo ' }';
echo '}'; } > /etc/nginx/sites-available/epicyon-i2p

View File

@ -281,49 +281,25 @@ echo "Creating nginx virtual host for ${ONION_DOMAIN}"
echo ' }';
echo '';
echo ' location / {';
echo ' proxy_http_version 1.1;';
echo ' client_max_body_size 31M;';
echo " proxy_hide_header Upgrade;";
echo ' proxy_hide_header Connection;';
echo " proxy_set_header Host \$http_host;";
echo " proxy_set_header X-Real-IP \$remote_addr;";
echo " proxy_set_header X-Forward-For \$proxy_add_x_forwarded_for;";
echo ' proxy_set_header X-Forward-Proto http;';
echo ' proxy_set_header X-Nginx-Proxy true;';
echo ' expires epoch;';
echo ' proxy_no_cache 1;';
echo ' proxy_temp_file_write_size 64k;';
echo ' proxy_connect_timeout 10080s;';
echo ' proxy_send_timeout 10080;';
echo ' proxy_read_timeout 10080;';
echo ' proxy_buffer_size 64k;';
echo ' proxy_buffers 16 32k;';
echo ' proxy_busy_buffers_size 64k;';
echo ' proxy_redirect off;';
echo ' proxy_request_buffering off;';
echo ' proxy_buffering on;';
echo ' proxy_cache my_cache;';
echo ' proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;';
echo " location ~ ^/(icons|images|media|emoji)/(.*)/(.*).(png|jpg|gif|webp|mp3|ogv|ogg|mp4) {";
echo ' expires 7d;';
echo " proxy_pass http://localhost:${EPICYON_PORT};";
echo ' }';
echo " location ~ ^/icons/(.*)/(like|repeat|calendar)(.*).(png|jpg|gif|webp|mp3|ogv|ogg|mp4) {";
echo ' expires epoch;';
echo ' proxy_no_cache 1;';
echo " proxy_pass http://localhost:${EPICYON_PORT};";
echo ' }';
echo " location ~ ^/icons/(like|repeat|calendar)(.*).(png|jpg|gif|webp|mp3|ogv|ogg|mp4) {";
echo ' expires epoch;';
echo ' proxy_no_cache 1;';
echo " proxy_pass http://localhost:${EPICYON_PORT};";
echo ' }';
echo " location ~ ^/users/(.*)/(image|banner).(png|jpg|gif|webp|mp3|ogv|ogg|mp4) {";
echo ' expires epoch;';
echo ' proxy_no_cache 1;';
echo " proxy_pass http://localhost:${EPICYON_PORT};";
echo ' }';
echo " proxy_pass http://localhost:${EPICYON_PORT};";
echo ' proxy_http_version 1.1;';
echo ' client_max_body_size 31M;';
echo " proxy_set_header Host \$http_host;";
echo " proxy_set_header X-Real-IP \$remote_addr;";
echo " proxy_set_header X-Forward-For \$proxy_add_x_forwarded_for;";
echo ' proxy_set_header X-Forward-Proto http;';
echo ' proxy_set_header X-Nginx-Proxy true;';
echo ' proxy_temp_file_write_size 64k;';
echo ' proxy_connect_timeout 10080s;';
echo ' proxy_send_timeout 10080;';
echo ' proxy_read_timeout 10080;';
echo ' proxy_buffer_size 64k;';
echo ' proxy_buffers 16 32k;';
echo ' proxy_busy_buffers_size 64k;';
echo ' proxy_redirect off;';
echo ' proxy_request_buffering off;';
echo ' proxy_buffering off;';
echo " proxy_pass http://localhost:${EPICYON_PORT};";
echo ' tcp_nodelay on;';
echo ' }';
echo '}'; } > "/etc/nginx/sites-available/${username}"

View File

@ -28,12 +28,41 @@ from utils import getSHA512
from utils import localActorUrl
def messageContentDigest(messageBodyJsonStr: str) -> str:
def messageContentDigest(messageBodyJsonStr: str, digestAlgorithm: str) -> str:
"""Returns the digest for the message body
"""
msg = messageBodyJsonStr.encode('utf-8')
hashResult = getSHA256(msg)
if digestAlgorithm == 'rsa-sha512' or \
digestAlgorithm == 'rsa-pss-sha512':
hashResult = getSHA512(msg)
else:
hashResult = getSHA256(msg)
return base64.b64encode(hashResult).decode('utf-8')
def getDigestPrefix(digestAlgorithm: str) -> str:
"""Returns the prefix for the message body digest
"""
if digestAlgorithm == 'rsa-sha512' or \
digestAlgorithm == 'rsa-pss-sha512':
return 'SHA-512'
return 'SHA-256'
def getDigestAlgorithmFromHeaders(httpHeaders: {}) -> str:
"""Returns the digest algorithm from http headers
"""
digestStr = None
if httpHeaders.get('digest'):
digestStr = httpHeaders['digest']
elif httpHeaders.get('Digest'):
digestStr = httpHeaders['Digest']
if digestStr:
if digestStr.startswith('SHA-512'):
return 'rsa-sha512'
return 'rsa-sha256'
def signPostHeaders(dateStr: str, privateKeyPem: str,
nickname: str,
domain: str, port: int,
@ -41,7 +70,9 @@ def signPostHeaders(dateStr: str, privateKeyPem: str,
path: str,
httpPrefix: str,
messageBodyJsonStr: str,
contentType: str) -> str:
contentType: str,
algorithm: str,
digestAlgorithm: str) -> str:
"""Returns a raw signature string that can be plugged into a header and
used to verify the authenticity of an HTTP transmission.
"""
@ -65,13 +96,15 @@ def signPostHeaders(dateStr: str, privateKeyPem: str,
'accept': contentType
}
else:
bodyDigest = messageContentDigest(messageBodyJsonStr)
bodyDigest = \
messageContentDigest(messageBodyJsonStr, digestAlgorithm)
digestPrefix = getDigestPrefix(digestAlgorithm)
contentLength = len(messageBodyJsonStr)
headers = {
'(request-target)': f'post {path}',
'host': toDomain,
'date': dateStr,
'digest': f'SHA-256={bodyDigest}',
'digest': f'{digestPrefix}={bodyDigest}',
'content-type': 'application/activity+json',
'content-length': str(contentLength)
}
@ -100,7 +133,7 @@ def signPostHeaders(dateStr: str, privateKeyPem: str,
# Put it into a valid HTTP signature format
signatureDict = {
'keyId': keyID,
'algorithm': 'rsa-sha256',
'algorithm': algorithm,
'headers': ' '.join(signedHeaderKeys),
'signature': signature
}
@ -116,7 +149,8 @@ def signPostHeadersNew(dateStr: str, privateKeyPem: str,
path: str,
httpPrefix: str,
messageBodyJsonStr: str,
algorithm: str, debug: bool) -> (str, str):
algorithm: str, digestAlgorithm: str,
debug: bool) -> (str, str):
"""Returns a raw signature strings that can be plugged into a header
as "Signature-Input" and "Signature"
used to verify the authenticity of an HTTP transmission.
@ -143,14 +177,15 @@ def signPostHeadersNew(dateStr: str, privateKeyPem: str,
'date': dateStr
}
else:
bodyDigest = messageContentDigest(messageBodyJsonStr)
bodyDigest = messageContentDigest(messageBodyJsonStr, digestAlgorithm)
digestPrefix = getDigestPrefix(digestAlgorithm)
contentLength = len(messageBodyJsonStr)
headers = {
'@request-target': f'post {path}',
'@created': str(secondsSinceEpoch),
'host': toDomain,
'date': dateStr,
'digest': f'SHA-256={bodyDigest}',
'digest': f'{digestPrefix}={bodyDigest}',
'content-type': 'application/activity+json',
'content-length': str(contentLength)
}
@ -210,6 +245,8 @@ def createSignedHeader(dateStr: str, privateKeyPem: str, nickname: str,
contentType: str) -> {}:
"""Note that the domain is the destination, not the sender
"""
algorithm = 'rsa-sha256'
digestAlgorithm = 'rsa-sha256'
headerDomain = getFullDomain(toDomain, toPort)
# if no date is given then create one
@ -230,15 +267,17 @@ def createSignedHeader(dateStr: str, privateKeyPem: str, nickname: str,
signatureHeader = \
signPostHeaders(dateStr, privateKeyPem, nickname,
domain, port, toDomain, toPort,
path, httpPrefix, None, contentType)
path, httpPrefix, None, contentType,
algorithm, None)
else:
bodyDigest = messageContentDigest(messageBodyJsonStr)
bodyDigest = messageContentDigest(messageBodyJsonStr, digestAlgorithm)
digestPrefix = getDigestPrefix(digestAlgorithm)
contentLength = len(messageBodyJsonStr)
headers = {
'(request-target)': f'post {path}',
'host': headerDomain,
'date': dateStr,
'digest': f'SHA-256={bodyDigest}',
'digest': f'{digestPrefix}={bodyDigest}',
'content-length': str(contentLength),
'content-type': contentType
}
@ -247,7 +286,7 @@ def createSignedHeader(dateStr: str, privateKeyPem: str, nickname: str,
domain, port,
toDomain, toPort,
path, httpPrefix, messageBodyJsonStr,
contentType)
contentType, algorithm, digestAlgorithm)
headers['signature'] = signatureHeader
return headers
@ -341,6 +380,7 @@ def verifyPostHeaders(httpPrefix: str,
# body (if a digest was included)
signedHeaderList = []
algorithm = 'rsa-sha256'
digestAlgorithm = 'rsa-sha256'
for signedHeader in signatureDict[requestTargetKey].split(fieldSep2):
signedHeader = signedHeader.strip()
if debug:
@ -387,7 +427,8 @@ def verifyPostHeaders(httpPrefix: str,
if messageBodyDigest:
bodyDigest = messageBodyDigest
else:
bodyDigest = messageContentDigest(messageBodyJsonStr)
bodyDigest = \
messageContentDigest(messageBodyJsonStr, digestAlgorithm)
signedHeaderList.append(f'digest: SHA-256={bodyDigest}')
elif signedHeader == 'content-length':
if headers.get(signedHeader):
@ -497,12 +538,12 @@ def verifyPostHeaders(httpPrefix: str,
else:
alg = hazutils.Prehashed(hashes.SHA256())
if algorithm == 'rsa-sha256' or algorithm == 'hs2019':
if digestAlgorithm == 'rsa-sha256':
headerDigest = getSHA256(signedHeaderText.encode('ascii'))
elif algorithm == 'rsa-sha512':
elif digestAlgorithm == 'rsa-sha512':
headerDigest = getSHA512(signedHeaderText.encode('ascii'))
else:
print('Unknown http signature algorithm: ' + algorithm)
print('Unknown http digest algorithm: ' + digestAlgorithm)
headerDigest = ''
paddingStr = padding.PKCS1v15()

View File

@ -60,6 +60,7 @@ from utils import localActorUrl
from utils import hasObjectStringType
from categories import getHashtagCategories
from categories import setHashtagCategory
from httpsig import getDigestAlgorithmFromHeaders
from httpsig import verifyPostHeaders
from session import createSession
from follow import followerApprovalActive
@ -549,7 +550,8 @@ def savePostToInboxQueue(baseDir: str, httpPrefix: str,
sharedInboxItem = True
digestStartTime = time.time()
digest = messageContentDigest(messageBytes)
digestAlgorithm = getDigestAlgorithmFromHeaders(httpHeaders)
digest = messageContentDigest(messageBytes, digestAlgorithm)
timeDiffStr = str(int((time.time() - digestStartTime) * 1000))
if debug:
while len(timeDiffStr) < 6:

View File

@ -23,6 +23,8 @@ from shutil import copyfile
from random import randint
from time import gmtime, strftime
from pprint import pprint
from httpsig import getDigestAlgorithmFromHeaders
from httpsig import getDigestPrefix
from httpsig import createSignedHeader
from httpsig import signPostHeaders
from httpsig import signPostHeadersNew
@ -390,7 +392,7 @@ def _testSignAndVerify() -> None:
pubkey.verify(signature2, headerDigest, paddingStr, alg)
def _testHttpSigNew():
def _testHttpSigNew(algorithm: str, digestAlgorithm: str):
print('testHttpSigNew')
httpPrefix = 'https'
port = 443
@ -401,8 +403,9 @@ def _testHttpSigNew():
pathStr = "/" + nickname + "?param=value&pet=dog HTTP/1.1"
domain = 'example.com'
dateStr = 'Tue, 20 Apr 2021 02:07:55 GMT'
digestStr = 'SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE='
bodyDigest = messageContentDigest(messageBodyJsonStr)
digestPrefix = getDigestPrefix(digestAlgorithm)
digestStr = digestPrefix + '=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE='
bodyDigest = messageContentDigest(messageBodyJsonStr, digestAlgorithm)
assert bodyDigest in digestStr
contentLength = 18
contentType = 'application/activity+json'
@ -477,7 +480,7 @@ def _testHttpSigNew():
headers = {
"host": domain,
"date": dateStr,
"digest": f'SHA-256={bodyDigest}',
"digest": f'{digestPrefix}={bodyDigest}',
"content-type": contentType,
"content-length": str(contentLength)
}
@ -486,7 +489,7 @@ def _testHttpSigNew():
domain, port,
domain, port,
pathStr, httpPrefix, messageBodyJsonStr,
'rsa-sha256', debug)
algorithm, digestAlgorithm, debug)
print('signatureIndexHeader1: ' + str(signatureIndexHeader))
print('signatureHeader1: ' + str(signatureHeader))
sigInput = "keyId=\"https://example.com/users/foo#main-key\"; " + \
@ -528,6 +531,8 @@ def _testHttpsigBase(withDigest: bool, baseDir: str):
os.mkdir(path)
os.chdir(path)
algorithm = 'rsa-sha256'
digestAlgorithm = 'rsa-sha256'
contentType = 'application/activity+json'
nickname = 'socrates'
hostDomain = 'someother.instance'
@ -563,23 +568,26 @@ def _testHttpsigBase(withDigest: bool, baseDir: str):
signPostHeaders(dateStr, privateKeyPem, nickname,
domain, port,
hostDomain, port,
boxpath, httpPrefix, None, contentType)
boxpath, httpPrefix, None, contentType,
algorithm, None)
else:
bodyDigest = messageContentDigest(messageBodyJsonStr)
digestPrefix = getDigestPrefix(digestAlgorithm)
bodyDigest = messageContentDigest(messageBodyJsonStr, digestAlgorithm)
contentLength = len(messageBodyJsonStr)
headers = {
'host': headersDomain,
'date': dateStr,
'digest': f'SHA-256={bodyDigest}',
'digest': f'{digestPrefix}={bodyDigest}',
'content-type': contentType,
'content-length': str(contentLength)
}
assert getDigestAlgorithmFromHeaders(headers) == digestAlgorithm
signatureHeader = \
signPostHeaders(dateStr, privateKeyPem, nickname,
domain, port,
hostDomain, port,
boxpath, httpPrefix, messageBodyJsonStr,
contentType)
contentType, algorithm, digestAlgorithm)
headers['signature'] = signatureHeader
GETmethod = not withDigest
@ -612,14 +620,16 @@ def _testHttpsigBase(withDigest: bool, baseDir: str):
'{"a key": "a value", "another key": "Fake GNUs", ' + \
'"yet another key": "More Fake GNUs"}'
contentLength = len(messageBodyJsonStr)
bodyDigest = messageContentDigest(messageBodyJsonStr)
digestPrefix = getDigestPrefix(digestAlgorithm)
bodyDigest = messageContentDigest(messageBodyJsonStr, digestAlgorithm)
headers = {
'host': domain,
'date': dateStr,
'digest': f'SHA-256={bodyDigest}',
'digest': f'{digestPrefix}={bodyDigest}',
'content-type': contentType,
'content-length': str(contentLength)
}
assert getDigestAlgorithmFromHeaders(headers) == digestAlgorithm
headers['signature'] = signatureHeader
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
boxpath, not GETmethod, None,
@ -5880,7 +5890,8 @@ def _testValidEmojiContent() -> None:
assert validEmojiContent('😄')
def _testHttpsigBaseNew(withDigest: bool, baseDir: str):
def _testHttpsigBaseNew(withDigest: bool, baseDir: str,
algorithm: str, digestAlgorithm: str) -> None:
print('testHttpsigNew(' + str(withDigest) + ')')
debug = True
@ -5926,23 +5937,25 @@ def _testHttpsigBaseNew(withDigest: bool, baseDir: str):
domain, port,
hostDomain, port,
boxpath, httpPrefix, messageBodyJsonStr,
'rsa-sha256', debug)
algorithm, digestAlgorithm, debug)
else:
bodyDigest = messageContentDigest(messageBodyJsonStr)
digestPrefix = getDigestPrefix(digestAlgorithm)
bodyDigest = messageContentDigest(messageBodyJsonStr, digestAlgorithm)
contentLength = len(messageBodyJsonStr)
headers = {
'host': headersDomain,
'date': dateStr,
'digest': f'SHA-256={bodyDigest}',
'digest': f'{digestPrefix}={bodyDigest}',
'content-type': contentType,
'content-length': str(contentLength)
}
assert getDigestAlgorithmFromHeaders(headers) == digestAlgorithm
signatureIndexHeader, signatureHeader = \
signPostHeadersNew(dateStr, privateKeyPem, nickname,
domain, port,
hostDomain, port,
boxpath, httpPrefix, messageBodyJsonStr,
'rsa-sha256', debug)
algorithm, digestAlgorithm, debug)
headers['signature'] = signatureHeader
headers['signature-input'] = signatureIndexHeader
@ -5979,14 +5992,16 @@ def _testHttpsigBaseNew(withDigest: bool, baseDir: str):
'{"a key": "a value", "another key": "Fake GNUs", ' + \
'"yet another key": "More Fake GNUs"}'
contentLength = len(messageBodyJsonStr)
bodyDigest = messageContentDigest(messageBodyJsonStr)
digestPrefix = getDigestPrefix(digestAlgorithm)
bodyDigest = messageContentDigest(messageBodyJsonStr, digestAlgorithm)
headers = {
'host': domain,
'date': dateStr,
'digest': f'SHA-256={bodyDigest}',
'digest': f'{digestPrefix}={bodyDigest}',
'content-type': contentType,
'content-length': str(contentLength)
}
assert getDigestAlgorithmFromHeaders(headers) == digestAlgorithm
headers['signature'] = signatureHeader
headers['signature-input'] = signatureIndexHeader
pprint(headers)
@ -6068,9 +6083,9 @@ def runAllTests():
_testActorParsing()
_testHttpsig(baseDir)
_testHttpSignedGET(baseDir)
_testHttpSigNew()
_testHttpsigBaseNew(True, baseDir)
_testHttpsigBaseNew(False, baseDir)
_testHttpSigNew('rsa-sha256', 'rsa-sha256')
_testHttpsigBaseNew(True, baseDir, 'rsa-sha256', 'rsa-sha256')
_testHttpsigBaseNew(False, baseDir, 'rsa-sha256', 'rsa-sha256')
_testCache()
_testThreads()
_testCreatePerson(baseDir)