epicyon/tests.py

5586 lines
216 KiB
Python
Raw Normal View History

2020-04-05 13:25:47 +00:00
__filename__ = "tests.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
2021-01-26 10:07:42 +00:00
__version__ = "1.2.0"
2020-04-05 13:25:47 +00:00
__maintainer__ = "Bob Mottram"
2021-09-10 16:14:50 +00:00
__email__ = "bob@libreserver.org"
2020-04-05 13:25:47 +00:00
__status__ = "Production"
2021-06-25 16:10:09 +00:00
__module_group__ = "Testing"
2020-04-05 13:25:47 +00:00
2019-06-30 20:14:03 +00:00
import time
2020-04-05 13:25:47 +00:00
import os
2019-06-30 21:20:02 +00:00
import shutil
2019-08-16 10:36:41 +00:00
import json
2021-05-09 19:11:05 +00:00
import datetime
2021-08-04 12:44:24 +00:00
from shutil import copyfile
2021-05-10 13:43:38 +00:00
from random import randint
2019-08-15 18:21:43 +00:00
from time import gmtime, strftime
2019-07-09 14:20:23 +00:00
from pprint import pprint
2019-06-30 20:14:03 +00:00
from httpsig import signPostHeaders
from httpsig import signPostHeadersNew
2019-06-30 20:14:03 +00:00
from httpsig import verifyPostHeaders
from httpsig import messageContentDigest
2019-06-30 20:14:03 +00:00
from cache import storePersonInCache
from cache import getPersonFromCache
from threads import threadWithTrace
2019-06-30 21:20:02 +00:00
from daemon import runDaemon
from session import createSession
2021-08-01 19:19:45 +00:00
from session import getJson
from posts import regenerateIndexForBox
2021-04-30 11:45:46 +00:00
from posts import removePostInteractions
2020-12-13 19:05:26 +00:00
from posts import getMentionedPeople
2020-08-25 19:35:55 +00:00
from posts import validContentWarning
2019-06-30 21:20:02 +00:00
from posts import deleteAllPosts
from posts import createPublicPost
2019-06-30 22:56:37 +00:00
from posts import sendPost
2019-07-05 14:39:24 +00:00
from posts import noOfFollowersOnDomain
from posts import groupFollowersByDomain
2019-07-12 22:29:10 +00:00
from posts import archivePostsForPerson
2019-07-16 10:19:04 +00:00
from posts import sendPostViaServer
2019-07-01 11:09:09 +00:00
from follow import clearFollows
from follow import clearFollowers
2019-07-16 21:38:06 +00:00
from follow import sendFollowRequestViaServer
2019-07-17 11:54:13 +00:00
from follow import sendUnfollowRequestViaServer
2021-06-20 15:45:29 +00:00
from siteactive import siteIsActive
2021-09-08 20:12:03 +00:00
from utils import canReplyTo
from utils import isGroupAccount
2021-08-11 09:15:46 +00:00
from utils import getActorLanguagesList
from utils import getCategoryTypes
2021-08-08 11:16:18 +00:00
from utils import getSupportedLanguages
2021-08-05 11:24:24 +00:00
from utils import setConfigParam
2021-07-31 11:56:28 +00:00
from utils import isGroupActor
2021-07-28 09:35:21 +00:00
from utils import dateStringToSeconds
from utils import dateSecondsToString
2021-07-20 20:39:26 +00:00
from utils import validPassword
2021-06-20 15:45:29 +00:00
from utils import userAgentDomain
from utils import camelCaseSplit
from utils import decodedHost
2020-12-16 11:19:16 +00:00
from utils import getFullDomain
2020-11-24 10:53:10 +00:00
from utils import validNickname
2020-11-08 11:24:43 +00:00
from utils import firstParagraphFromString
2020-08-23 11:13:35 +00:00
from utils import removeIdEnding
from utils import updateRecentPostsCache
2019-07-06 19:24:52 +00:00
from utils import followPerson
2019-08-21 16:35:46 +00:00
from utils import getNicknameFromActor
from utils import getDomainFromActor
2019-09-29 18:48:34 +00:00
from utils import copytree
from utils import loadJson
from utils import saveJson
2019-10-12 12:45:53 +00:00
from utils import getStatusNumber
2020-09-25 13:21:56 +00:00
from utils import getFollowersOfPerson
from utils import removeHtml
from utils import dangerousMarkup
2021-07-13 21:59:53 +00:00
from utils import acctDir
2021-03-12 12:04:34 +00:00
from pgp import extractPGPPublicKey
2021-03-17 20:18:00 +00:00
from pgp import pgpPublicKeyUpload
2021-03-12 12:04:34 +00:00
from utils import containsPGPPublicKey
2019-06-30 21:20:02 +00:00
from follow import followerOfPerson
2020-12-22 13:57:24 +00:00
from follow import unfollowAccount
from follow import unfollowerOfAccount
2019-07-06 13:49:25 +00:00
from follow import sendFollowRequest
2019-07-03 10:04:23 +00:00
from person import createPerson
2021-07-30 19:20:49 +00:00
from person import createGroup
from person import setDisplayNickname
2019-07-03 10:04:23 +00:00
from person import setBio
2020-06-15 12:37:53 +00:00
# from person import generateRSAKey
2019-07-19 10:01:24 +00:00
from skills import setSkillLevel
2021-05-16 15:10:39 +00:00
from skills import actorSkillValue
2021-05-13 14:13:27 +00:00
from skills import setSkillsFromDict
2021-05-16 15:10:39 +00:00
from skills import actorHasSkill
from roles import setRolesFromList
2019-07-18 15:09:23 +00:00
from roles import setRole
2021-05-16 15:10:39 +00:00
from roles import actorHasRole
from auth import constantTimeStringCheck
2019-07-03 18:24:44 +00:00
from auth import createBasicAuthHeader
from auth import authorizeBasic
from auth import storeBasicCredentials
2019-07-11 12:29:31 +00:00
from like import likePost
from like import sendLikeViaServer
2019-07-11 17:55:10 +00:00
from announce import announcePublic
2019-07-16 19:07:45 +00:00
from announce import sendAnnounceViaServer
from city import parseNogoString
from city import spoofGeolocation
from city import pointInNogo
from media import getImageDimensions
2019-07-12 19:26:54 +00:00
from media import getMediaPath
2019-08-30 15:50:20 +00:00
from media import getAttachmentMediaType
2019-07-17 17:16:48 +00:00
from delete import sendDeleteViaServer
2020-08-21 18:32:16 +00:00
from inbox import jsonPostAllowsComments
from inbox import validInbox
2019-07-18 11:35:48 +00:00
from inbox import validInboxFilenames
2020-12-22 13:57:24 +00:00
from categories import guessHashtagCategory
2021-08-07 17:03:41 +00:00
from content import getPriceFromString
from content import limitRepeatedWords
2021-07-06 16:29:03 +00:00
from content import switchWords
from content import extractTextFieldsInPOST
from content import validHashTag
from content import htmlReplaceEmailQuote
2020-08-02 17:01:12 +00:00
from content import htmlReplaceQuoteMarks
2020-12-13 14:48:45 +00:00
from content import dangerousCSS
2019-09-01 08:55:05 +00:00
from content import addWebLinks
2019-09-29 18:48:34 +00:00
from content import replaceEmojiFromTags
from content import addHtmlTags
2019-11-04 20:39:14 +00:00
from content import removeLongWords
2020-05-12 09:34:58 +00:00
from content import replaceContentDuplicates
from content import removeTextFormatting
2020-10-11 09:33:31 +00:00
from content import removeHtmlTag
from theme import updateDefaultThemesList
2019-11-23 13:04:11 +00:00
from theme import setCSSparam
from linked_data_sig import generateJsonSignature
from linked_data_sig import verifyJsonSignature
2020-10-17 12:05:41 +00:00
from newsdaemon import hashtagRuleTree
2020-10-17 17:36:10 +00:00
from newsdaemon import hashtagRuleResolve
2020-10-25 10:06:54 +00:00
from newswire import getNewswireTags
2020-11-22 18:43:01 +00:00
from newswire import parseFeedDate
from newswire import limitWordLengths
2021-01-22 13:32:37 +00:00
from mastoapiv1 import getMastoApiV1IdFromNickname
from mastoapiv1 import getNicknameFromMastoApiV1Id
2021-02-02 21:08:33 +00:00
from webapp_post import prepareHtmlPostNickname
from speaker import speakerReplaceLinks
from markdown import markdownToHtml
2021-07-19 10:07:29 +00:00
from languages import setActorLanguages
from languages import getActorLanguages
2021-07-20 10:45:04 +00:00
from languages import getLinksFromContent
2021-07-20 18:02:42 +00:00
from languages import addLinksToContent
2021-08-08 11:16:18 +00:00
from languages import libretranslate
from languages import libretranslateLanguages
from shares import authorizeSharedItems
from shares import generateSharedItemFederationTokens
2021-07-26 12:20:07 +00:00
from shares import createSharedItemFederationToken
from shares import updateSharedItemFederationToken
from shares import mergeSharedItemTokens
from shares import sendShareViaServer
2021-08-04 12:04:35 +00:00
from shares import getSharedItemsCatalogViaServer
2019-06-30 20:14:03 +00:00
2021-07-30 19:20:49 +00:00
testServerGroupRunning = False
2020-04-05 13:25:47 +00:00
testServerAliceRunning = False
testServerBobRunning = False
testServerEveRunning = False
2021-07-30 19:20:49 +00:00
thrGroup = None
2020-04-05 13:25:47 +00:00
thrAlice = None
thrBob = None
thrEve = None
2019-06-30 21:27:25 +00:00
2021-09-01 16:35:24 +00:00
def _testHttpSignedGET():
print('testHttpSignedGET')
2021-09-01 16:22:00 +00:00
boxpath = "/users/Actor"
host = "epicyon.libreserver.org"
content_length = "0"
user_agent = "http.rb/4.4.1 (Mastodon/3.4.1; +https://octodon.social/)"
dateStr = 'Wed, 01 Sep 2021 16:11:10 GMT'
accept_encoding = 'gzip'
2021-09-08 12:19:01 +00:00
accept = \
2021-09-08 12:44:50 +00:00
'application/activity+json, application/ld+json'
2021-09-01 16:35:24 +00:00
signature = \
'keyId="https://octodon.social/actor#main-key",' + \
'algorithm="rsa-sha256",' + \
'headers="(request-target) host date accept",' + \
'signature="Fe53PS9A2OSP4x+W/svhA' + \
'jUKHBvnAR73Ez+H32au7DQklLk08Lvm8al' + \
'LS7pCor28yfyx+DfZADgq6G1mLLRZo0OOn' + \
'PFSog7DhdcygLhBUMS0KlT5KVGwUS0tw' + \
'jdiHv4OC83RiCr/ZySBgOv65YLHYmGCi5B' + \
'IqSZJRkqi8+SLmLGESlNOEzKu+jIxOBY' + \
'mEEdIpNrDeE5YrFKpfTC3vS2GnxGOo5J/4' + \
'lB2h+dlUpso+sv5rDz1d1FsqRWK8waV7' + \
'4HUfLV+qbgYRceOTyZIi50vVqLvt9CTQes' + \
'KZHG3GrrPfaBuvoUbR4MCM3BUvpB7EzL' + \
'9F17Y+Ea9mo8zjqzZm8HaZQ=="'
2021-09-01 16:06:02 +00:00
publicKeyPem = \
'-----BEGIN PUBLIC KEY-----\n' + \
2021-09-01 16:35:24 +00:00
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMII' + \
'BCgKCAQEA1XT+ov/i4LDYuaXCwh4r\n' + \
'2rVfWtnz68wnFx3knwymwtRoAc/SFGzp9ye' + \
'5ogG1uPcbe7MeirZHhaBICynPlL32\n' + \
's9OYootI7MsQWn+vu7azxiXO7qcTPByvGcl' + \
'0vpLhtT/ApmlMintkRTVXdzBdJVM0\n' + \
'UsmYKg6U+IHNL+a1gURHGXep2Ih0BJMh4Aa' + \
'DbaID6jtpJZvbIkYgJ4IJucOe+A3T\n' + \
'YPMwkBA84ew+hso+vKQfTunyDInuPQbEzrA' + \
'zMJXEHS7IpBhdS4/cEox86BoDJ/q0\n' + \
'KOEOUpUDniFYWb9k1+9B387OviRDLIcLxNZ' + \
'nf+bNq8d+CwEXY2xGsToBle/q74d8\n' + \
2021-09-01 16:22:00 +00:00
'BwIDAQAB\n' + \
2021-09-01 16:06:02 +00:00
'-----END PUBLIC KEY-----\n'
headers = {
2021-09-01 16:22:00 +00:00
"user-agent": user_agent,
"content-length": content_length,
"host": host,
"date": dateStr,
"accept": accept,
"accept-encoding": accept_encoding,
2021-09-01 16:06:02 +00:00
"signature": signature
}
httpPrefix = 'https'
2021-09-01 16:22:00 +00:00
debug = True
2021-09-01 16:06:02 +00:00
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
2021-09-01 16:22:00 +00:00
boxpath, True, None,
'', debug, True)
2021-09-01 16:35:24 +00:00
# Change a single character and the signature should fail
headers['date'] = headers['date'].replace(':10', ':11')
assert not verifyPostHeaders(httpPrefix, publicKeyPem, headers,
boxpath, True, None,
'', debug, True)
2021-09-01 16:06:02 +00:00
def _testHttpSigNew():
print('testHttpSigNew')
messageBodyJson = {"hello": "world"}
messageBodyJsonStr = json.dumps(messageBodyJson)
publicKeyPem = \
'-----BEGIN RSA PUBLIC KEY-----\n' + \
'MIIBCgKCAQEAhAKYdtoeoy8zcAcR874L8' + \
'cnZxKzAGwd7v36APp7Pv6Q2jdsPBRrw\n' + \
'WEBnez6d0UDKDwGbc6nxfEXAy5mbhgajz' + \
'rw3MOEt8uA5txSKobBpKDeBLOsdJKFq\n' + \
'MGmXCQvEG7YemcxDTRPxAleIAgYYRjTSd' + \
'/QBwVW9OwNFhekro3RtlinV0a75jfZg\n' + \
'kne/YiktSvLG34lw2zqXBDTC5NHROUqGT' + \
'lML4PlNZS5Ri2U4aCNx2rUPRcKIlE0P\n' + \
'uKxI4T+HIaFpv8+rdV6eUgOrB2xeI1dSF' + \
'Fn/nnv5OoZJEIB+VmuKn3DCUcCZSFlQ\n' + \
'PSXSfBDiUGhwOw76WuSSsf1D4b/vLoJ10wIDAQAB\n' + \
'-----END RSA PUBLIC KEY-----\n'
privateKeyPem = \
'-----BEGIN RSA PRIVATE KEY-----\n' + \
'MIIEqAIBAAKCAQEAhAKYdtoeoy8zcAcR8' + \
'74L8cnZxKzAGwd7v36APp7Pv6Q2jdsP\n' + \
'BRrwWEBnez6d0UDKDwGbc6nxfEXAy5mbh' + \
'gajzrw3MOEt8uA5txSKobBpKDeBLOsd\n' + \
'JKFqMGmXCQvEG7YemcxDTRPxAleIAgYYR' + \
'jTSd/QBwVW9OwNFhekro3RtlinV0a75\n' + \
'jfZgkne/YiktSvLG34lw2zqXBDTC5NHRO' + \
'UqGTlML4PlNZS5Ri2U4aCNx2rUPRcKI\n' + \
'lE0PuKxI4T+HIaFpv8+rdV6eUgOrB2xeI' + \
'1dSFFn/nnv5OoZJEIB+VmuKn3DCUcCZ\n' + \
'SFlQPSXSfBDiUGhwOw76WuSSsf1D4b/vL' + \
'oJ10wIDAQABAoIBAG/JZuSWdoVHbi56\n' + \
'vjgCgkjg3lkO1KrO3nrdm6nrgA9P9qaPj' + \
'xuKoWaKO1cBQlE1pSWp/cKncYgD5WxE\n' + \
'CpAnRUXG2pG4zdkzCYzAh1i+c34L6oZoH' + \
'sirK6oNcEnHveydfzJL5934egm6p8DW\n' + \
'+m1RQ70yUt4uRc0YSor+q1LGJvGQHReF0' + \
'WmJBZHrhz5e63Pq7lE0gIwuBqL8SMaA\n' + \
'yRXtK+JGxZpImTq+NHvEWWCu09SCq0r83' + \
'8ceQI55SvzmTkwqtC+8AT2zFviMZkKR\n' + \
'Qo6SPsrqItxZWRty2izawTF0Bf5S2VAx7' + \
'O+6t3wBsQ1sLptoSgX3QblELY5asI0J\n' + \
'YFz7LJECgYkAsqeUJmqXE3LP8tYoIjMIA' + \
'KiTm9o6psPlc8CrLI9CH0UbuaA2JCOM\n' + \
'cCNq8SyYbTqgnWlB9ZfcAm/cFpA8tYci9' + \
'm5vYK8HNxQr+8FS3Qo8N9RJ8d0U5Csw\n' + \
'DzMYfRghAfUGwmlWj5hp1pQzAuhwbOXFt' + \
'xKHVsMPhz1IBtF9Y8jvgqgYHLbmyiu1\n' + \
'mwJ5AL0pYF0G7x81prlARURwHo0Yf52kE' + \
'w1dxpx+JXER7hQRWQki5/NsUEtv+8RT\n' + \
'qn2m6qte5DXLyn83b1qRscSdnCCwKtKWU' + \
'ug5q2ZbwVOCJCtmRwmnP131lWRYfj67\n' + \
'B/xJ1ZA6X3GEf4sNReNAtaucPEelgR2ns' + \
'N0gKQKBiGoqHWbK1qYvBxX2X3kbPDkv\n' + \
'9C+celgZd2PW7aGYLCHq7nPbmfDV0yHcW' + \
'jOhXZ8jRMjmANVR/eLQ2EfsRLdW69bn\n' + \
'f3ZD7JS1fwGnO3exGmHO3HZG+6AvberKY' + \
'VYNHahNFEw5TsAcQWDLRpkGybBcxqZo\n' + \
'81YCqlqidwfeO5YtlO7etx1xLyqa2NsCe' + \
'G9A86UjG+aeNnXEIDk1PDK+EuiThIUa\n' + \
'/2IxKzJKWl1BKr2d4xAfR0ZnEYuRrbeDQ' + \
'YgTImOlfW6/GuYIxKYgEKCFHFqJATAG\n' + \
'IxHrq1PDOiSwXd2GmVVYyEmhZnbcp8Cxa' + \
'EMQoevxAta0ssMK3w6UsDtvUvYvF22m\n' + \
'qQKBiD5GwESzsFPy3Ga0MvZpn3D6EJQLg' + \
'snrtUPZx+z2Ep2x0xc5orneB5fGyF1P\n' + \
'WtP+fG5Q6Dpdz3LRfm+KwBCWFKQjg7uTx' + \
'cjerhBWEYPmEMKYwTJF5PBG9/ddvHLQ\n' + \
'EQeNC8fHGg4UXU8mhHnSBt3EA10qQJfRD' + \
's15M38eG2cYwB1PZpDHScDnDA0=\n' + \
'-----END RSA PRIVATE KEY-----'
sigInput = \
'sig1=(date); alg=rsa-sha256; keyId="test-key-b"'
sig = \
'sig1=:HtXycCl97RBVkZi66ADKnC9c5eSSlb57GnQ4KFqNZplOpNfxqk62' + \
'JzZ484jXgLvoOTRaKfR4hwyxlcyb+BWkVasApQovBSdit9Ml/YmN2IvJDPncrlhPD' + \
'VDv36Z9/DiSO+RNHD7iLXugdXo1+MGRimW1RmYdenl/ITeb7rjfLZ4b9VNnLFtVWw' + \
'rjhAiwIqeLjodVImzVc5srrk19HMZNuUejK6I3/MyN3+3U8tIRW4LWzx6ZgGZUaEE' + \
'P0aBlBkt7Fj0Tt5/P5HNW/Sa/m8smxbOHnwzAJDa10PyjzdIbywlnWIIWtZKPPsoV' + \
'oKVopUWEU3TNhpWmaVhFrUL/O6SN3w==:'
# "hs2019", using RSASSA-PSS [RFC8017] and SHA-512 [RFC6234]
# sigInput = \
# 'sig1=(*request-target, *created, host, date, ' + \
# 'cache-control, x-empty-header, x-example); keyId="test-key-a"; ' + \
# 'alg=hs2019; created=1402170695; expires=1402170995'
# sig = \
# 'sig1=:K2qGT5srn2OGbOIDzQ6kYT+ruaycnDAAUpKv+ePFfD0RAxn/1BUe' + \
# 'Zx/Kdrq32DrfakQ6bPsvB9aqZqognNT6be4olHROIkeV879RrsrObury8L9SCEibe' + \
# 'oHyqU/yCjphSmEdd7WD+zrchK57quskKwRefy2iEC5S2uAH0EPyOZKWlvbKmKu5q4' + \
# 'CaB8X/I5/+HLZLGvDiezqi6/7p2Gngf5hwZ0lSdy39vyNMaaAT0tKo6nuVw0S1MVg' + \
# '1Q7MpWYZs0soHjttq0uLIA3DIbQfLiIvK6/l0BdWTU7+2uQj7lBkQAsFZHoA96ZZg' + \
# 'FquQrXRlmYOh+Hx5D9fJkXcXe5tmAg==:'
nickname = 'foo'
boxpath = '/' + nickname
# headers = {
# "*request-target": "get " + boxpath,
# "*created": "1402170695",
# "host": "example.org",
# "date": "Tue, 07 Jun 2014 20:51:35 GMT",
# "cache-control": "max-age=60, must-revalidate",
# "x-emptyheader": "",
# "x-example": "Example header with some whitespace.",
# "x-dictionary": "b=2",
# "x-dictionary": "a=1",
# "x-list": "(a, b, c)",
# "Signature-Input": sigInput,
# "Signature": sig
# }
dateStr = "Tue, 07 Jun 2014 20:51:35 GMT"
2021-04-04 21:30:26 +00:00
secondsSinceEpoch = 1402174295
domain = "example.com"
port = 443
headers = {
2021-02-22 18:27:04 +00:00
"*created": str(secondsSinceEpoch),
"*request-target": "post /foo?param=value&pet=dog",
"host": domain,
"date": dateStr,
"content-type": "application/json",
"digest": "SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=",
"content-length": "18",
"Signature-Input": sigInput,
"Signature": sig
}
httpPrefix = 'https'
debug = False
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
boxpath, False, None,
2021-04-04 21:30:26 +00:00
messageBodyJsonStr, debug, True)
# make a deliberate mistake
headers['Signature'] = headers['Signature'].replace('V', 'B')
assert not verifyPostHeaders(httpPrefix, publicKeyPem, headers,
boxpath, False, None,
2021-04-04 21:30:26 +00:00
messageBodyJsonStr, debug, True)
# test signing
bodyDigest = messageContentDigest(messageBodyJsonStr)
contentLength = len(messageBodyJsonStr)
headers = {
"host": domain,
"date": dateStr,
"digest": f'SHA-256={bodyDigest}',
"content-type": "application/json",
"content-length": str(contentLength)
}
signatureIndexHeader, signatureHeader = \
signPostHeadersNew(dateStr, privateKeyPem, nickname,
domain, port,
domain, port,
boxpath, httpPrefix, messageBodyJsonStr,
'rsa-sha256')
2021-04-04 08:19:35 +00:00
expectedIndexHeader = \
'keyId="https://example.com/users/foo#main-key"; ' + \
2021-02-22 18:27:04 +00:00
'alg=hs2019; created=' + str(secondsSinceEpoch) + '; ' + \
'sig1=(*request-target, *created, host, date, ' + \
'digest, content-type, content-length)'
2021-04-04 08:19:35 +00:00
if signatureIndexHeader != expectedIndexHeader:
2021-04-04 08:27:46 +00:00
print('Unexpected new http header: ' + signatureIndexHeader)
2021-04-04 20:34:42 +00:00
print('Should be: ' + expectedIndexHeader)
2021-04-04 08:19:35 +00:00
assert signatureIndexHeader == expectedIndexHeader
assert signatureHeader == \
2021-04-04 21:30:26 +00:00
'sig1=:euX3O1KSTYXN9/oR2qFezswWm9FbrjtRymK7xBpXNQvTs' + \
'XehtrNdD8nELZKzPXMvMz7PaJd6V+fjzpHoZ9upTdqqQLK2Iwml' + \
'p4BlHqW6Aopd7sZFCWFq7/Amm5oaizpp3e0jb5XISS5m3cRKuoi' + \
'LM0x+OudmAoYGi0TEEJk8bpnJAXfVCDfmOyL3XNqQeShQHeOANG' + \
'okiKktj8ff+KLYLaPTAJkob1k/EhoPIkbw/YzAY8IZjWQNMkf+F' + \
'JChApQ5HnDCQPwD5xV9eGzBpAf6D0G19xiTmQye4Hn6tAs3fy3V' + \
'/aYa/GhW2pSrctDnAKIi4imj9joppr3CB8gqgXZOPQ==:'
def _testHttpsigBase(withDigest):
2019-06-30 20:14:03 +00:00
print('testHttpsig(' + str(withDigest) + ')')
2019-08-09 09:46:33 +00:00
2020-04-05 13:25:47 +00:00
baseDir = os.getcwd()
path = baseDir + '/.testHttpsigBase'
2019-08-09 09:46:33 +00:00
if os.path.isdir(path):
shutil.rmtree(path)
os.mkdir(path)
os.chdir(path)
2020-04-05 13:25:47 +00:00
contentType = 'application/activity+json'
nickname = 'socrates'
domain = 'argumentative.social'
httpPrefix = 'https'
port = 5576
password = 'SuperSecretPassword'
privateKeyPem, publicKeyPem, person, wfEndpoint = \
2020-07-12 12:31:28 +00:00
createPerson(path, nickname, domain, port, httpPrefix,
False, False, password)
2019-08-09 09:46:33 +00:00
assert privateKeyPem
2020-04-05 13:25:47 +00:00
messageBodyJson = {
2020-03-22 20:36:19 +00:00
"a key": "a value",
"another key": "A string",
"yet another key": "Another string"
}
2020-04-05 13:25:47 +00:00
messageBodyJsonStr = json.dumps(messageBodyJson)
2019-07-01 09:31:02 +00:00
2020-12-16 11:19:16 +00:00
headersDomain = getFullDomain(domain, port)
2019-07-01 09:31:02 +00:00
2020-04-05 13:25:47 +00:00
dateStr = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime())
boxpath = '/inbox'
2019-06-30 20:14:03 +00:00
if not withDigest:
2020-04-05 13:25:47 +00:00
headers = {
2020-03-22 20:36:19 +00:00
'host': headersDomain,
'date': dateStr,
'accept': 'application/json'
2020-03-22 20:36:19 +00:00
}
2020-04-05 13:25:47 +00:00
signatureHeader = \
signPostHeaders(dateStr, privateKeyPem, nickname,
domain, port,
domain, port,
2019-08-16 13:47:01 +00:00
boxpath, httpPrefix, None)
2019-06-30 20:14:03 +00:00
else:
2020-04-05 13:25:47 +00:00
bodyDigest = messageContentDigest(messageBodyJsonStr)
contentLength = len(messageBodyJsonStr)
headers = {
2020-03-22 20:36:19 +00:00
'host': headersDomain,
'date': dateStr,
'digest': f'SHA-256={bodyDigest}',
'content-type': contentType,
'content-length': str(contentLength)
}
2020-04-05 13:25:47 +00:00
signatureHeader = \
signPostHeaders(dateStr, privateKeyPem, nickname,
domain, port,
domain, port,
boxpath, httpPrefix, messageBodyJsonStr)
2019-07-01 09:31:02 +00:00
2020-04-05 13:25:47 +00:00
headers['signature'] = signatureHeader
2021-09-01 18:46:28 +00:00
GETmethod = not withDigest
2020-04-05 13:25:47 +00:00
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
2021-09-01 18:46:28 +00:00
boxpath, GETmethod, None,
2020-04-05 13:25:47 +00:00
messageBodyJsonStr, False)
2019-11-12 18:21:52 +00:00
if withDigest:
# everything correct except for content-length
2020-04-05 13:25:47 +00:00
headers['content-length'] = str(contentLength + 2)
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
2021-09-01 18:46:28 +00:00
boxpath, GETmethod, None,
2020-04-05 13:25:47 +00:00
messageBodyJsonStr, False) is False
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
2021-09-01 18:46:28 +00:00
'/parambulator' + boxpath, GETmethod, None,
2020-04-05 13:25:47 +00:00
messageBodyJsonStr, False) is False
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
2021-09-01 18:46:28 +00:00
boxpath, not GETmethod, None,
2020-04-05 13:25:47 +00:00
messageBodyJsonStr, False) is False
2019-06-30 20:14:03 +00:00
if not withDigest:
# fake domain
2020-04-05 13:25:47 +00:00
headers = {
2020-03-22 20:36:19 +00:00
'host': 'bogon.domain',
'date': dateStr,
'content-type': 'application/json'
}
2019-06-30 20:14:03 +00:00
else:
# correct domain but fake message
2020-04-05 13:25:47 +00:00
messageBodyJsonStr = \
'{"a key": "a value", "another key": "Fake GNUs", ' + \
'"yet another key": "More Fake GNUs"}'
contentLength = len(messageBodyJsonStr)
bodyDigest = messageContentDigest(messageBodyJsonStr)
headers = {
2020-03-22 20:36:19 +00:00
'host': domain,
'date': dateStr,
'digest': f'SHA-256={bodyDigest}',
'content-type': contentType,
'content-length': str(contentLength)
}
2020-04-05 13:25:47 +00:00
headers['signature'] = signatureHeader
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
2021-09-01 18:46:28 +00:00
boxpath, not GETmethod, None,
2020-04-05 13:25:47 +00:00
messageBodyJsonStr, False) is False
2019-11-12 18:21:52 +00:00
2019-08-09 09:46:33 +00:00
os.chdir(baseDir)
shutil.rmtree(path)
2019-06-30 20:14:03 +00:00
2020-04-05 13:25:47 +00:00
def _testHttpsig():
_testHttpsigBase(True)
_testHttpsigBase(False)
2019-06-30 20:14:03 +00:00
2020-04-05 13:25:47 +00:00
def _testCache():
2019-06-30 20:14:03 +00:00
print('testCache')
2020-04-05 13:25:47 +00:00
personUrl = "cat@cardboard.box"
personJson = {
"id": 123456,
"test": "This is a test"
}
personCache = {}
storePersonInCache(None, personUrl, personJson, personCache, True)
result = getPersonFromCache(None, personUrl, personCache, True)
2020-04-05 13:25:47 +00:00
assert result['id'] == 123456
assert result['test'] == 'This is a test'
2019-06-30 20:14:03 +00:00
def _testThreadsFunction(param: str):
2019-06-30 20:14:03 +00:00
for i in range(10000):
time.sleep(2)
2020-04-05 13:25:47 +00:00
def _testThreads():
2019-06-30 20:14:03 +00:00
print('testThreads')
2020-04-05 13:25:47 +00:00
thr = \
threadWithTrace(target=_testThreadsFunction,
2020-04-05 13:25:47 +00:00
args=('test',),
daemon=True)
2019-06-30 20:14:03 +00:00
thr.start()
2020-12-18 15:29:12 +00:00
assert thr.is_alive() is True
2019-06-30 20:14:03 +00:00
time.sleep(1)
thr.kill()
thr.join()
2020-12-18 15:29:12 +00:00
assert thr.is_alive() is False
2019-06-30 21:20:02 +00:00
2020-04-05 13:25:47 +00:00
def createServerAlice(path: str, domain: str, port: int,
bobAddress: str, federationList: [],
hasFollows: bool, hasPosts: bool,
2020-09-27 19:27:24 +00:00
sendThreads: []):
2020-04-05 13:25:47 +00:00
print('Creating test server: Alice on port ' + str(port))
2019-06-30 21:20:02 +00:00
if os.path.isdir(path):
shutil.rmtree(path)
os.mkdir(path)
os.chdir(path)
sharedItemsFederatedDomains = []
2021-07-18 09:55:49 +00:00
systemLanguage = 'en'
2020-04-05 13:25:47 +00:00
nickname = 'alice'
httpPrefix = 'http'
2020-06-09 11:03:59 +00:00
proxyType = None
2020-04-05 13:25:47 +00:00
password = 'alicepass'
maxReplies = 64
domainMaxPostsPerDay = 1000
accountMaxPostsPerDay = 1000
allowDeletion = True
lowBandwidth = True
2020-04-05 13:25:47 +00:00
privateKeyPem, publicKeyPem, person, wfEndpoint = \
2020-07-12 12:31:28 +00:00
createPerson(path, nickname, domain, port, httpPrefix, True,
False, password)
2020-04-05 13:25:47 +00:00
deleteAllPosts(path, nickname, domain, 'inbox')
deleteAllPosts(path, nickname, domain, 'outbox')
assert setSkillLevel(path, nickname, domain, 'hacking', 90)
assert setRole(path, nickname, domain, 'guru')
2019-07-06 13:49:25 +00:00
if hasFollows:
2020-04-05 13:25:47 +00:00
followPerson(path, nickname, domain, 'bob', bobAddress,
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(path, nickname, domain, 'bob', bobAddress,
2021-07-30 16:06:34 +00:00
federationList, False, False)
2019-07-06 13:49:25 +00:00
if hasPosts:
testFollowersOnly = False
testSaveToFile = True
2020-12-22 21:27:46 +00:00
clientToServer = False
testCommentsEnabled = True
testAttachImageFilename = None
testMediaType = None
testImageDescription = None
2021-05-09 19:29:53 +00:00
testCity = 'London, England'
2021-07-01 20:41:17 +00:00
testInReplyTo = None
testInReplyToAtomUri = None
testSubject = None
testSchedulePost = False
testEventDate = None
testEventTime = None
testLocation = None
testIsArticle = False
2021-08-08 16:52:32 +00:00
conversationId = None
2020-04-05 13:25:47 +00:00
createPublicPost(path, nickname, domain, port, httpPrefix,
"No wise fish would go anywhere without a porpoise",
testFollowersOnly,
testSaveToFile,
clientToServer,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
2021-07-01 20:41:17 +00:00
testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId,
lowBandwidth)
2020-04-05 13:25:47 +00:00
createPublicPost(path, nickname, domain, port, httpPrefix,
"Curiouser and curiouser!",
testFollowersOnly,
testSaveToFile,
clientToServer,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
2021-07-01 20:41:17 +00:00
testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId,
lowBandwidth)
2020-04-05 13:25:47 +00:00
createPublicPost(path, nickname, domain, port, httpPrefix,
"In the gardens of memory, in the palace " +
"of dreams, that is where you and I shall meet",
testFollowersOnly,
testSaveToFile,
clientToServer,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
2021-07-01 20:41:17 +00:00
testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId,
lowBandwidth)
2021-08-01 19:19:45 +00:00
regenerateIndexForBox(path, nickname, domain, 'outbox')
2019-06-30 21:27:25 +00:00
global testServerAliceRunning
2020-04-05 13:25:47 +00:00
testServerAliceRunning = True
maxMentions = 10
maxEmoji = 10
onionDomain = None
i2pDomain = None
allowLocalNetworkAccess = True
maxNewswirePosts = 20
dormantMonths = 3
sendThreadsTimeoutMins = 30
maxFollowers = 10
verifyAllSignatures = True
2021-02-15 22:06:53 +00:00
brochMode = False
showNodeInfoAccounts = True
showNodeInfoVersion = True
2021-05-09 19:29:53 +00:00
city = 'London, England'
2021-06-09 15:19:30 +00:00
logLoginFailures = False
2021-06-20 17:48:50 +00:00
userAgentsBlocked = []
maxLikeCount = 10
defaultReplyIntervalHours = 9999999999
2019-06-30 21:20:02 +00:00
print('Server running: Alice')
runDaemon(defaultReplyIntervalHours,
lowBandwidth, maxLikeCount,
sharedItemsFederatedDomains,
userAgentsBlocked,
2021-06-20 13:25:18 +00:00
logLoginFailures, city,
2021-05-09 19:11:05 +00:00
showNodeInfoAccounts,
showNodeInfoVersion,
brochMode,
2021-02-15 22:06:53 +00:00
verifyAllSignatures,
sendThreadsTimeoutMins,
dormantMonths, maxNewswirePosts,
allowLocalNetworkAccess,
2048, False, True, False, False, True, maxFollowers,
0, 100, 1024, 5, False,
0, False, 1, False, False, False,
2020-10-07 09:10:42 +00:00
5, True, True, 'en', __version__,
"instanceId", False, path, domain,
onionDomain, i2pDomain, None, port, port,
2020-04-05 13:25:47 +00:00
httpPrefix, federationList, maxMentions, maxEmoji, False,
2020-06-09 11:03:59 +00:00
proxyType, maxReplies,
2020-04-05 13:25:47 +00:00
domainMaxPostsPerDay, accountMaxPostsPerDay,
allowDeletion, True, True, False, sendThreads,
2020-07-12 12:31:28 +00:00
False)
2020-04-05 13:25:47 +00:00
def createServerBob(path: str, domain: str, port: int,
aliceAddress: str, federationList: [],
hasFollows: bool, hasPosts: bool,
2020-09-27 19:27:24 +00:00
sendThreads: []):
2020-04-05 13:25:47 +00:00
print('Creating test server: Bob on port ' + str(port))
2019-06-30 21:20:02 +00:00
if os.path.isdir(path):
shutil.rmtree(path)
os.mkdir(path)
os.chdir(path)
sharedItemsFederatedDomains = []
2021-07-18 09:55:49 +00:00
systemLanguage = 'en'
2020-04-05 13:25:47 +00:00
nickname = 'bob'
httpPrefix = 'http'
2020-06-09 11:03:59 +00:00
proxyType = None
2020-04-05 13:25:47 +00:00
clientToServer = False
password = 'bobpass'
maxReplies = 64
domainMaxPostsPerDay = 1000
accountMaxPostsPerDay = 1000
allowDeletion = True
lowBandwidth = True
2020-04-05 13:25:47 +00:00
privateKeyPem, publicKeyPem, person, wfEndpoint = \
2020-07-12 12:31:28 +00:00
createPerson(path, nickname, domain, port, httpPrefix, True,
False, password)
2020-04-05 13:25:47 +00:00
deleteAllPosts(path, nickname, domain, 'inbox')
deleteAllPosts(path, nickname, domain, 'outbox')
2021-08-01 13:25:11 +00:00
if hasFollows and aliceAddress:
2020-04-05 13:25:47 +00:00
followPerson(path, nickname, domain,
2021-07-30 16:06:34 +00:00
'alice', aliceAddress, federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(path, nickname, domain,
2021-07-30 16:06:34 +00:00
'alice', aliceAddress, federationList, False, False)
2019-07-06 13:49:25 +00:00
if hasPosts:
testFollowersOnly = False
testSaveToFile = True
testCommentsEnabled = True
testAttachImageFilename = None
2020-12-22 21:27:46 +00:00
testImageDescription = None
testMediaType = None
2021-05-09 19:29:53 +00:00
testCity = 'London, England'
2021-07-01 20:41:17 +00:00
testInReplyTo = None
testInReplyToAtomUri = None
testSubject = None
testSchedulePost = False
testEventDate = None
testEventTime = None
testLocation = None
testIsArticle = False
2021-08-08 16:52:32 +00:00
conversationId = None
2020-04-05 13:25:47 +00:00
createPublicPost(path, nickname, domain, port, httpPrefix,
"It's your life, live it your way.",
testFollowersOnly,
testSaveToFile,
clientToServer,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
2021-07-01 20:41:17 +00:00
testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId,
lowBandwidth)
2020-04-05 13:25:47 +00:00
createPublicPost(path, nickname, domain, port, httpPrefix,
"One of the things I've realised is that " +
"I am very simple",
testFollowersOnly,
testSaveToFile,
clientToServer,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
2021-07-01 20:41:17 +00:00
testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId,
lowBandwidth)
2020-04-05 13:25:47 +00:00
createPublicPost(path, nickname, domain, port, httpPrefix,
"Quantum physics is a bit of a passion of mine",
testFollowersOnly,
testSaveToFile,
clientToServer,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
2021-07-01 20:41:17 +00:00
testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId,
lowBandwidth)
2021-08-01 19:19:45 +00:00
regenerateIndexForBox(path, nickname, domain, 'outbox')
2019-06-30 21:27:25 +00:00
global testServerBobRunning
2020-04-05 13:25:47 +00:00
testServerBobRunning = True
maxMentions = 10
maxEmoji = 10
onionDomain = None
i2pDomain = None
allowLocalNetworkAccess = True
maxNewswirePosts = 20
dormantMonths = 3
sendThreadsTimeoutMins = 30
maxFollowers = 10
verifyAllSignatures = True
2021-02-15 22:06:53 +00:00
brochMode = False
showNodeInfoAccounts = True
showNodeInfoVersion = True
2021-05-09 19:29:53 +00:00
city = 'London, England'
2021-06-09 15:19:30 +00:00
logLoginFailures = False
2021-06-20 17:48:50 +00:00
userAgentsBlocked = []
maxLikeCount = 10
defaultReplyIntervalHours = 9999999999
2019-06-30 21:20:02 +00:00
print('Server running: Bob')
runDaemon(defaultReplyIntervalHours,
lowBandwidth, maxLikeCount,
sharedItemsFederatedDomains,
userAgentsBlocked,
2021-06-20 13:25:18 +00:00
logLoginFailures, city,
2021-05-09 19:11:05 +00:00
showNodeInfoAccounts,
showNodeInfoVersion,
brochMode,
2021-02-15 22:06:53 +00:00
verifyAllSignatures,
sendThreadsTimeoutMins,
dormantMonths, maxNewswirePosts,
allowLocalNetworkAccess,
2048, False, True, False, False, True, maxFollowers,
0, 100, 1024, 5, False, 0,
False, 1, False, False, False,
2020-10-07 09:10:42 +00:00
5, True, True, 'en', __version__,
"instanceId", False, path, domain,
onionDomain, i2pDomain, None, port, port,
2020-04-05 13:25:47 +00:00
httpPrefix, federationList, maxMentions, maxEmoji, False,
2020-06-09 11:03:59 +00:00
proxyType, maxReplies,
2020-04-05 13:25:47 +00:00
domainMaxPostsPerDay, accountMaxPostsPerDay,
allowDeletion, True, True, False, sendThreads,
2020-07-12 12:31:28 +00:00
False)
2020-04-05 13:25:47 +00:00
def createServerEve(path: str, domain: str, port: int, federationList: [],
hasFollows: bool, hasPosts: bool,
2020-09-27 19:27:24 +00:00
sendThreads: []):
2020-04-05 13:25:47 +00:00
print('Creating test server: Eve on port ' + str(port))
if os.path.isdir(path):
shutil.rmtree(path)
os.mkdir(path)
os.chdir(path)
sharedItemsFederatedDomains = []
2020-04-05 13:25:47 +00:00
nickname = 'eve'
httpPrefix = 'http'
2020-06-09 11:03:59 +00:00
proxyType = None
2020-04-05 13:25:47 +00:00
password = 'evepass'
maxReplies = 64
allowDeletion = True
privateKeyPem, publicKeyPem, person, wfEndpoint = \
2020-07-12 12:31:28 +00:00
createPerson(path, nickname, domain, port, httpPrefix, True,
False, password)
2020-04-05 13:25:47 +00:00
deleteAllPosts(path, nickname, domain, 'inbox')
deleteAllPosts(path, nickname, domain, 'outbox')
global testServerEveRunning
2020-04-05 13:25:47 +00:00
testServerEveRunning = True
maxMentions = 10
maxEmoji = 10
onionDomain = None
i2pDomain = None
allowLocalNetworkAccess = True
maxNewswirePosts = 20
dormantMonths = 3
sendThreadsTimeoutMins = 30
maxFollowers = 10
verifyAllSignatures = True
2021-02-15 22:06:53 +00:00
brochMode = False
showNodeInfoAccounts = True
showNodeInfoVersion = True
2021-05-09 19:29:53 +00:00
city = 'London, England'
2021-06-09 15:19:30 +00:00
logLoginFailures = False
2021-06-20 17:48:50 +00:00
userAgentsBlocked = []
maxLikeCount = 10
lowBandwidth = True
defaultReplyIntervalHours = 9999999999
print('Server running: Eve')
runDaemon(defaultReplyIntervalHours,
lowBandwidth, maxLikeCount,
sharedItemsFederatedDomains,
userAgentsBlocked,
2021-06-20 13:25:18 +00:00
logLoginFailures, city,
2021-05-09 19:11:05 +00:00
showNodeInfoAccounts,
showNodeInfoVersion,
brochMode,
2021-02-15 22:06:53 +00:00
verifyAllSignatures,
sendThreadsTimeoutMins,
dormantMonths, maxNewswirePosts,
allowLocalNetworkAccess,
2048, False, True, False, False, True, maxFollowers,
0, 100, 1024, 5, False, 0,
False, 1, False, False, False,
2020-10-07 09:10:42 +00:00
5, True, True, 'en', __version__,
"instanceId", False, path, domain,
onionDomain, i2pDomain, None, port, port,
2020-04-05 13:25:47 +00:00
httpPrefix, federationList, maxMentions, maxEmoji, False,
2020-06-09 11:03:59 +00:00
proxyType, maxReplies, allowDeletion, True, True, False,
sendThreads, False)
2020-04-05 13:25:47 +00:00
2021-07-30 19:20:49 +00:00
def createServerGroup(path: str, domain: str, port: int,
federationList: [],
hasFollows: bool, hasPosts: bool,
sendThreads: []):
print('Creating test server: Group on port ' + str(port))
if os.path.isdir(path):
shutil.rmtree(path)
os.mkdir(path)
os.chdir(path)
sharedItemsFederatedDomains = []
# systemLanguage = 'en'
nickname = 'testgroup'
httpPrefix = 'http'
proxyType = None
password = 'testgrouppass'
maxReplies = 64
domainMaxPostsPerDay = 1000
accountMaxPostsPerDay = 1000
allowDeletion = True
privateKeyPem, publicKeyPem, person, wfEndpoint = \
createGroup(path, nickname, domain, port, httpPrefix, True,
password)
deleteAllPosts(path, nickname, domain, 'inbox')
deleteAllPosts(path, nickname, domain, 'outbox')
global testServerGroupRunning
testServerGroupRunning = True
maxMentions = 10
maxEmoji = 10
onionDomain = None
i2pDomain = None
allowLocalNetworkAccess = True
maxNewswirePosts = 20
dormantMonths = 3
sendThreadsTimeoutMins = 30
maxFollowers = 10
verifyAllSignatures = True
brochMode = False
showNodeInfoAccounts = True
showNodeInfoVersion = True
city = 'London, England'
logLoginFailures = False
userAgentsBlocked = []
maxLikeCount = 10
lowBandwidth = True
defaultReplyIntervalHours = 9999999999
2021-07-30 19:20:49 +00:00
print('Server running: Group')
runDaemon(defaultReplyIntervalHours,
lowBandwidth, maxLikeCount,
sharedItemsFederatedDomains,
2021-07-30 19:20:49 +00:00
userAgentsBlocked,
logLoginFailures, city,
showNodeInfoAccounts,
showNodeInfoVersion,
brochMode,
verifyAllSignatures,
sendThreadsTimeoutMins,
dormantMonths, maxNewswirePosts,
allowLocalNetworkAccess,
2048, False, True, False, False, True, maxFollowers,
0, 100, 1024, 5, False,
0, False, 1, False, False, False,
5, True, True, 'en', __version__,
"instanceId", False, path, domain,
onionDomain, i2pDomain, None, port, port,
httpPrefix, federationList, maxMentions, maxEmoji, False,
proxyType, maxReplies,
domainMaxPostsPerDay, accountMaxPostsPerDay,
allowDeletion, True, True, False, sendThreads,
False)
2019-06-30 21:20:02 +00:00
def testPostMessageBetweenServers():
print('Testing sending message from one server to the inbox of another')
2019-06-30 21:27:25 +00:00
global testServerAliceRunning
global testServerBobRunning
2020-04-05 13:25:47 +00:00
testServerAliceRunning = False
testServerBobRunning = False
2019-06-30 21:27:25 +00:00
2021-07-18 09:55:49 +00:00
systemLanguage = 'en'
2020-04-05 13:25:47 +00:00
httpPrefix = 'http'
2020-06-09 11:03:59 +00:00
proxyType = None
2019-06-30 22:56:37 +00:00
2020-04-05 13:25:47 +00:00
baseDir = os.getcwd()
if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests')
os.mkdir(baseDir + '/.tests')
2019-06-30 21:20:02 +00:00
# create the servers
2020-04-05 13:25:47 +00:00
aliceDir = baseDir + '/.tests/alice'
aliceDomain = '127.0.0.50'
alicePort = 61935
aliceAddress = aliceDomain + ':' + str(alicePort)
bobDir = baseDir + '/.tests/bob'
bobDomain = '127.0.0.100'
bobPort = 61936
federationList = [bobDomain, aliceDomain]
aliceSendThreads = []
bobSendThreads = []
bobAddress = bobDomain + ':' + str(bobPort)
2019-07-11 12:29:31 +00:00
2020-02-19 12:27:21 +00:00
global thrAlice
if thrAlice:
2020-12-18 15:29:12 +00:00
while thrAlice.is_alive():
2020-02-19 12:27:21 +00:00
thrAlice.stop()
time.sleep(1)
thrAlice.kill()
2020-04-05 13:25:47 +00:00
thrAlice = \
threadWithTrace(target=createServerAlice,
args=(aliceDir, aliceDomain, alicePort, bobAddress,
federationList, False, False,
2020-09-27 19:27:24 +00:00
aliceSendThreads),
2020-04-05 13:25:47 +00:00
daemon=True)
2020-02-19 12:27:21 +00:00
global thrBob
if thrBob:
2020-12-18 15:29:12 +00:00
while thrBob.is_alive():
2020-02-19 12:27:21 +00:00
thrBob.stop()
time.sleep(1)
thrBob.kill()
2020-04-05 13:25:47 +00:00
thrBob = \
threadWithTrace(target=createServerBob,
args=(bobDir, bobDomain, bobPort, aliceAddress,
federationList, False, False,
2020-09-27 19:27:24 +00:00
bobSendThreads),
2020-04-05 13:25:47 +00:00
daemon=True)
2019-07-01 21:01:43 +00:00
thrAlice.start()
2019-06-30 21:20:02 +00:00
thrBob.start()
2020-12-18 15:29:12 +00:00
assert thrAlice.is_alive() is True
assert thrBob.is_alive() is True
2019-06-30 21:20:02 +00:00
2019-06-30 21:27:25 +00:00
# wait for both servers to be running
while not (testServerAliceRunning and testServerBobRunning):
time.sleep(1)
2020-03-22 21:16:02 +00:00
2019-07-04 20:25:19 +00:00
time.sleep(1)
2019-06-30 21:20:02 +00:00
2019-07-11 12:29:31 +00:00
print('\n\n*******************************************************')
2019-06-30 22:56:37 +00:00
print('Alice sends to Bob')
os.chdir(aliceDir)
2020-06-09 11:03:59 +00:00
sessionAlice = createSession(proxyType)
2020-04-05 13:25:47 +00:00
inReplyTo = None
inReplyToAtomUri = None
subject = None
alicePostLog = []
followersOnly = False
saveToFile = True
clientToServer = False
ccUrl = None
alicePersonCache = {}
aliceCachedWebfingers = {}
2021-08-05 11:24:24 +00:00
aliceSharedItemsFederatedDomains = []
aliceSharedItemFederationTokens = {}
2020-04-05 13:25:47 +00:00
attachedImageFilename = baseDir + '/img/logo.png'
testImageWidth, testImageHeight = \
getImageDimensions(attachedImageFilename)
assert testImageWidth
assert testImageHeight
2020-04-05 13:25:47 +00:00
mediaType = getAttachmentMediaType(attachedImageFilename)
attachedImageDescription = 'Logo'
isArticle = False
2021-05-09 19:29:53 +00:00
city = 'London, England'
2019-07-11 12:29:31 +00:00
# nothing in Alice's outbox
2020-04-05 13:25:47 +00:00
outboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox'
assert len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 0
lowBandwidth = False
signingPrivateKeyPem = None
2020-04-05 13:25:47 +00:00
sendResult = \
sendPost(signingPrivateKeyPem, __version__,
2020-04-05 13:25:47 +00:00
sessionAlice, aliceDir, 'alice', aliceDomain, alicePort,
'bob', bobDomain, bobPort, ccUrl, httpPrefix,
'Why is a mouse when it spins? ' +
'यह एक परीक्षण है #sillyquestion',
followersOnly,
2020-08-21 17:40:50 +00:00
saveToFile, clientToServer, True,
attachedImageFilename, mediaType,
2021-05-09 19:11:05 +00:00
attachedImageDescription, city, federationList,
2020-04-05 13:25:47 +00:00
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
2021-08-05 11:24:24 +00:00
alicePersonCache, isArticle, systemLanguage,
aliceSharedItemsFederatedDomains,
aliceSharedItemFederationTokens, lowBandwidth,
2021-08-05 11:24:24 +00:00
inReplyTo, inReplyToAtomUri, subject)
2020-04-05 13:25:47 +00:00
print('sendResult: ' + str(sendResult))
queuePath = bobDir + '/accounts/bob@' + bobDomain + '/queue'
inboxPath = bobDir + '/accounts/bob@' + bobDomain + '/inbox'
mPath = getMediaPath()
mediaPath = aliceDir + '/' + mPath
2019-07-07 22:25:22 +00:00
for i in range(30):
2019-07-04 20:36:12 +00:00
if os.path.isdir(inboxPath):
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) > 0:
if len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath,
name))]) == 1:
if len([name for name in os.listdir(mediaPath)
if os.path.isfile(os.path.join(mediaPath,
name))]) > 0:
if len([name for name in os.listdir(queuePath)
if os.path.isfile(os.path.join(queuePath,
name))]) == 0:
2019-10-19 17:50:05 +00:00
break
2019-07-01 21:01:43 +00:00
time.sleep(1)
2019-07-09 08:52:53 +00:00
2020-12-06 15:05:22 +00:00
# check that a news account exists
newsActorDir = aliceDir + '/accounts/news@' + aliceDomain
print("newsActorDir: " + newsActorDir)
assert os.path.isdir(newsActorDir)
newsActorFile = newsActorDir + '.json'
assert os.path.isfile(newsActorFile)
newsActorJson = loadJson(newsActorFile)
assert newsActorJson
assert newsActorJson.get("id")
# check the id of the news actor
print('News actor Id: ' + newsActorJson["id"])
assert (newsActorJson["id"] ==
httpPrefix + '://' + aliceAddress + '/users/news')
2019-07-12 19:26:54 +00:00
# Image attachment created
2020-04-05 13:25:47 +00:00
assert len([name for name in os.listdir(mediaPath)
if os.path.isfile(os.path.join(mediaPath, name))]) > 0
2019-07-11 12:29:31 +00:00
# inbox item created
2020-04-05 13:25:47 +00:00
assert len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) == 1
2019-07-11 12:29:31 +00:00
# queue item removed
2020-04-05 13:25:47 +00:00
testval = len([name for name in os.listdir(queuePath)
if os.path.isfile(os.path.join(queuePath, name))])
print('queuePath: ' + queuePath + ' '+str(testval))
assert testval == 0
assert validInbox(bobDir, 'bob', bobDomain)
assert validInboxFilenames(bobDir, 'bob', bobDomain,
aliceDomain, alicePort)
2019-11-09 09:50:58 +00:00
print('Check that message received from Alice contains the expected text')
for name in os.listdir(inboxPath):
2020-04-05 13:25:47 +00:00
filename = os.path.join(inboxPath, name)
2019-11-09 09:50:58 +00:00
assert os.path.isfile(filename)
2020-04-05 13:25:47 +00:00
receivedJson = loadJson(filename, 0)
if receivedJson:
2019-11-09 09:50:58 +00:00
pprint(receivedJson['object']['content'])
2019-11-09 09:52:09 +00:00
assert receivedJson
2020-04-05 13:25:47 +00:00
assert 'Why is a mouse when it spins?' in \
receivedJson['object']['content']
assert 'Why is a mouse when it spins?' in \
receivedJson['object']['contentMap'][systemLanguage]
2019-11-09 09:52:09 +00:00
assert 'यह एक परीक्षण है' in receivedJson['object']['content']
print('Check that message received from Alice contains an attachment')
assert receivedJson['object']['attachment']
assert len(receivedJson['object']['attachment']) == 1
attached = receivedJson['object']['attachment'][0]
pprint(attached)
assert attached.get('type')
assert attached.get('url')
assert attached['mediaType'] == 'image/png'
assert '/media/' in attached['url']
assert attached['url'].endswith('.png')
assert attached.get('width')
assert attached.get('height')
assert attached['width'] > 0
assert attached['height'] > 0
2019-11-09 09:52:09 +00:00
2019-07-11 12:59:00 +00:00
print('\n\n*******************************************************')
print("Bob likes Alice's post")
aliceDomainStr = aliceDomain + ':' + str(alicePort)
2020-04-05 13:25:47 +00:00
followerOfPerson(bobDir, 'bob', bobDomain, 'alice',
2021-07-30 16:06:34 +00:00
aliceDomainStr, federationList, False, False)
bobDomainStr = bobDomain + ':' + str(bobPort)
2020-04-05 13:25:47 +00:00
followPerson(aliceDir, 'alice', aliceDomain, 'bob',
2021-07-30 16:06:34 +00:00
bobDomainStr, federationList, False, False)
2020-04-05 13:25:47 +00:00
2020-06-09 11:03:59 +00:00
sessionBob = createSession(proxyType)
2020-04-05 13:25:47 +00:00
bobPostLog = []
bobPersonCache = {}
bobCachedWebfingers = {}
statusNumber = None
outboxPostFilename = None
outboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox'
2019-07-11 12:59:00 +00:00
for name in os.listdir(outboxPath):
if '#statuses#' in name:
2020-04-05 13:25:47 +00:00
statusNumber = \
int(name.split('#statuses#')[1].replace('.json', ''))
outboxPostFilename = outboxPath + '/' + name
assert statusNumber > 0
2019-07-11 12:59:00 +00:00
assert outboxPostFilename
2020-04-05 13:25:47 +00:00
assert likePost({}, sessionBob, bobDir, federationList,
'bob', bobDomain, bobPort, httpPrefix,
'alice', aliceDomain, alicePort, [],
statusNumber, False, bobSendThreads, bobPostLog,
bobPersonCache, bobCachedWebfingers,
True, __version__, signingPrivateKeyPem)
2019-07-11 12:59:00 +00:00
for i in range(20):
if 'likes' in open(outboxPostFilename).read():
break
time.sleep(1)
2020-04-05 13:25:47 +00:00
alicePostJson = loadJson(outboxPostFilename, 0)
if alicePostJson:
2019-07-11 12:59:00 +00:00
pprint(alicePostJson)
2020-03-22 21:16:02 +00:00
2019-07-11 12:59:00 +00:00
assert 'likes' in open(outboxPostFilename).read()
2019-07-11 17:55:10 +00:00
print('\n\n*******************************************************')
print("Bob repeats Alice's post")
2020-04-05 13:25:47 +00:00
objectUrl = \
httpPrefix + '://' + aliceDomain + ':' + str(alicePort) + \
'/users/alice/statuses/' + str(statusNumber)
inboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/inbox'
outboxPath = bobDir + '/accounts/bob@' + bobDomain + '/outbox'
outboxBeforeAnnounceCount = \
len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))])
beforeAnnounceCount = \
len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
print('inbox items before announce: ' + str(beforeAnnounceCount))
print('outbox items before announce: ' + str(outboxBeforeAnnounceCount))
assert outboxBeforeAnnounceCount == 0
assert beforeAnnounceCount == 0
announcePublic(sessionBob, bobDir, federationList,
'bob', bobDomain, bobPort, httpPrefix,
objectUrl,
False, bobSendThreads, bobPostLog,
bobPersonCache, bobCachedWebfingers,
True, __version__, signingPrivateKeyPem)
2020-04-05 13:25:47 +00:00
announceMessageArrived = False
outboxMessageArrived = False
2019-07-11 19:31:02 +00:00
for i in range(10):
time.sleep(1)
2020-03-27 19:54:41 +00:00
if not os.path.isdir(inboxPath):
continue
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) > 0:
outboxMessageArrived = True
2020-03-27 19:54:41 +00:00
print('Announce created by Bob')
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) > 0:
announceMessageArrived = True
2020-03-27 19:54:41 +00:00
print('Announce message sent to Alice!')
if announceMessageArrived and outboxMessageArrived:
break
2020-04-05 13:25:47 +00:00
afterAnnounceCount = \
len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
outboxAfterAnnounceCount = \
len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))])
print('inbox items after announce: ' + str(afterAnnounceCount))
print('outbox items after announce: ' + str(outboxAfterAnnounceCount))
assert afterAnnounceCount == beforeAnnounceCount+1
assert outboxAfterAnnounceCount == outboxBeforeAnnounceCount + 1
2019-06-30 21:20:02 +00:00
# stop the servers
thrAlice.kill()
thrAlice.join()
2020-12-18 15:29:12 +00:00
assert thrAlice.is_alive() is False
2019-06-30 21:20:02 +00:00
thrBob.kill()
thrBob.join()
2020-12-18 15:29:12 +00:00
assert thrBob.is_alive() is False
2019-06-30 21:20:02 +00:00
os.chdir(baseDir)
shutil.rmtree(aliceDir)
shutil.rmtree(bobDir)
2020-04-05 13:25:47 +00:00
2019-10-15 09:31:10 +00:00
def testFollowBetweenServers():
print('Testing sending a follow request from one server to another')
global testServerAliceRunning
global testServerBobRunning
2020-04-05 13:25:47 +00:00
testServerAliceRunning = False
testServerBobRunning = False
2019-10-15 09:31:10 +00:00
2021-07-18 09:55:49 +00:00
systemLanguage = 'en'
2020-04-05 13:25:47 +00:00
httpPrefix = 'http'
2020-06-09 11:03:59 +00:00
proxyType = None
2020-04-05 13:25:47 +00:00
federationList = []
2019-10-15 09:31:10 +00:00
2020-04-05 13:25:47 +00:00
baseDir = os.getcwd()
if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests')
os.mkdir(baseDir + '/.tests')
2019-10-15 09:31:10 +00:00
# create the servers
2020-04-05 13:25:47 +00:00
aliceDir = baseDir + '/.tests/alice'
aliceDomain = '127.0.0.47'
alicePort = 61935
aliceSendThreads = []
aliceAddress = aliceDomain + ':' + str(alicePort)
bobDir = baseDir + '/.tests/bob'
bobDomain = '127.0.0.79'
bobPort = 61936
bobSendThreads = []
bobAddress = bobDomain + ':' + str(bobPort)
2020-02-19 12:27:21 +00:00
global thrAlice
if thrAlice:
2020-12-18 15:29:12 +00:00
while thrAlice.is_alive():
2020-02-19 12:27:21 +00:00
thrAlice.stop()
time.sleep(1)
thrAlice.kill()
2020-04-05 13:25:47 +00:00
thrAlice = \
threadWithTrace(target=createServerAlice,
args=(aliceDir, aliceDomain, alicePort, bobAddress,
federationList, False, False,
2020-09-27 19:27:24 +00:00
aliceSendThreads),
2020-04-05 13:25:47 +00:00
daemon=True)
2019-10-15 09:31:10 +00:00
2020-02-19 12:27:21 +00:00
global thrBob
if thrBob:
2020-12-18 15:29:12 +00:00
while thrBob.is_alive():
2020-02-19 12:27:21 +00:00
thrBob.stop()
time.sleep(1)
thrBob.kill()
2020-04-05 13:25:47 +00:00
thrBob = \
threadWithTrace(target=createServerBob,
args=(bobDir, bobDomain, bobPort, aliceAddress,
federationList, False, False,
2020-09-27 19:27:24 +00:00
bobSendThreads),
2020-04-05 13:25:47 +00:00
daemon=True)
2019-10-15 09:31:10 +00:00
thrAlice.start()
thrBob.start()
2020-12-18 15:29:12 +00:00
assert thrAlice.is_alive() is True
assert thrBob.is_alive() is True
2019-10-15 09:31:10 +00:00
# wait for all servers to be running
2020-04-05 13:25:47 +00:00
ctr = 0
2019-10-15 09:31:10 +00:00
while not (testServerAliceRunning and testServerBobRunning):
time.sleep(1)
2020-04-05 13:25:47 +00:00
ctr += 1
if ctr > 60:
2019-10-15 09:31:10 +00:00
break
2020-04-05 13:25:47 +00:00
print('Alice online: ' + str(testServerAliceRunning))
print('Bob online: ' + str(testServerBobRunning))
assert ctr <= 60
2019-10-15 09:31:10 +00:00
time.sleep(1)
# In the beginning all was calm and there were no follows
print('*********************************************************')
print('Alice sends a follow request to Bob')
os.chdir(aliceDir)
2020-06-09 11:03:59 +00:00
sessionAlice = createSession(proxyType)
2020-04-05 13:25:47 +00:00
inReplyTo = None
inReplyToAtomUri = None
subject = None
alicePostLog = []
followersOnly = False
saveToFile = True
clientToServer = False
ccUrl = None
alicePersonCache = {}
aliceCachedWebfingers = {}
alicePostLog = []
bobActor = httpPrefix + '://' + bobAddress + '/users/bob'
signingPrivateKeyPem = None
2020-04-05 13:25:47 +00:00
sendResult = \
sendFollowRequest(sessionAlice, aliceDir,
'alice', aliceDomain, alicePort, httpPrefix,
'bob', bobDomain, bobActor,
bobPort, httpPrefix,
2020-04-05 13:25:47 +00:00
clientToServer, federationList,
aliceSendThreads, alicePostLog,
aliceCachedWebfingers, alicePersonCache,
True, __version__, signingPrivateKeyPem)
2020-04-05 13:25:47 +00:00
print('sendResult: ' + str(sendResult))
2019-10-15 09:31:10 +00:00
2020-12-23 10:58:50 +00:00
for t in range(16):
2020-04-05 13:25:47 +00:00
if os.path.isfile(bobDir + '/accounts/bob@' +
bobDomain + '/followers.txt'):
if os.path.isfile(aliceDir + '/accounts/alice@' +
aliceDomain + '/following.txt'):
if os.path.isfile(aliceDir + '/accounts/alice@' +
aliceDomain + '/followingCalendar.txt'):
break
2019-10-15 09:31:10 +00:00
time.sleep(1)
2020-04-05 13:25:47 +00:00
assert validInbox(bobDir, 'bob', bobDomain)
assert validInboxFilenames(bobDir, 'bob', bobDomain,
aliceDomain, alicePort)
assert 'alice@' + aliceDomain in open(bobDir + '/accounts/bob@' +
bobDomain + '/followers.txt').read()
assert 'bob@' + bobDomain in open(aliceDir + '/accounts/alice@' +
aliceDomain + '/following.txt').read()
assert 'bob@' + bobDomain in open(aliceDir + '/accounts/alice@' +
aliceDomain +
'/followingCalendar.txt').read()
2021-07-31 11:56:28 +00:00
assert not isGroupActor(aliceDir, bobActor, alicePersonCache)
assert not isGroupAccount(aliceDir, 'alice', aliceDomain)
2019-10-15 09:31:10 +00:00
print('\n\n*********************************************************')
print('Alice sends a message to Bob')
2020-04-05 13:25:47 +00:00
alicePostLog = []
alicePersonCache = {}
aliceCachedWebfingers = {}
2021-08-05 11:24:24 +00:00
aliceSharedItemsFederatedDomains = []
aliceSharedItemFederationTokens = {}
2020-04-05 13:25:47 +00:00
alicePostLog = []
isArticle = False
2021-05-09 19:29:53 +00:00
city = 'London, England'
lowBandwidth = False
signingPrivateKeyPem = None
2020-04-05 13:25:47 +00:00
sendResult = \
sendPost(signingPrivateKeyPem, __version__,
2020-04-05 13:25:47 +00:00
sessionAlice, aliceDir, 'alice', aliceDomain, alicePort,
'bob', bobDomain, bobPort, ccUrl,
httpPrefix, 'Alice message', followersOnly, saveToFile,
2020-08-21 17:40:50 +00:00
clientToServer, True,
2021-05-09 19:11:05 +00:00
None, None, None, city, federationList,
2020-04-05 13:25:47 +00:00
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
2021-08-05 11:24:24 +00:00
alicePersonCache, isArticle, systemLanguage,
aliceSharedItemsFederatedDomains,
aliceSharedItemFederationTokens, lowBandwidth,
2021-08-05 11:24:24 +00:00
inReplyTo, inReplyToAtomUri, subject)
2020-04-05 13:25:47 +00:00
print('sendResult: ' + str(sendResult))
queuePath = bobDir + '/accounts/bob@' + bobDomain + '/queue'
inboxPath = bobDir + '/accounts/bob@' + bobDomain + '/inbox'
aliceMessageArrived = False
for i in range(20):
time.sleep(1)
if os.path.isdir(inboxPath):
if len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) > 0:
aliceMessageArrived = True
print('Alice message sent to Bob!')
break
assert aliceMessageArrived is True
print('Message from Alice to Bob succeeded')
# stop the servers
thrAlice.kill()
thrAlice.join()
assert thrAlice.is_alive() is False
thrBob.kill()
thrBob.join()
assert thrBob.is_alive() is False
# queue item removed
time.sleep(4)
assert len([name for name in os.listdir(queuePath)
if os.path.isfile(os.path.join(queuePath, name))]) == 0
os.chdir(baseDir)
shutil.rmtree(baseDir + '/.tests')
def testSharedItemsFederation():
print('Testing federation of shared items between Alice and Bob')
global testServerAliceRunning
global testServerBobRunning
testServerAliceRunning = False
testServerBobRunning = False
systemLanguage = 'en'
httpPrefix = 'http'
proxyType = None
federationList = []
baseDir = os.getcwd()
if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests')
os.mkdir(baseDir + '/.tests')
# create the servers
aliceDir = baseDir + '/.tests/alice'
aliceDomain = '127.0.0.74'
alicePort = 61917
aliceSendThreads = []
aliceAddress = aliceDomain + ':' + str(alicePort)
bobDir = baseDir + '/.tests/bob'
bobDomain = '127.0.0.81'
bobPort = 61983
bobSendThreads = []
bobAddress = bobDomain + ':' + str(bobPort)
bobPassword = 'bobpass'
bobCachedWebfingers = {}
bobPersonCache = {}
global thrAlice
if thrAlice:
while thrAlice.is_alive():
thrAlice.stop()
time.sleep(1)
thrAlice.kill()
thrAlice = \
threadWithTrace(target=createServerAlice,
args=(aliceDir, aliceDomain, alicePort, bobAddress,
federationList, False, False,
aliceSendThreads),
daemon=True)
global thrBob
if thrBob:
while thrBob.is_alive():
thrBob.stop()
time.sleep(1)
thrBob.kill()
thrBob = \
threadWithTrace(target=createServerBob,
args=(bobDir, bobDomain, bobPort, aliceAddress,
federationList, False, False,
bobSendThreads),
daemon=True)
thrAlice.start()
thrBob.start()
assert thrAlice.is_alive() is True
assert thrBob.is_alive() is True
# wait for all servers to be running
ctr = 0
while not (testServerAliceRunning and testServerBobRunning):
time.sleep(1)
ctr += 1
if ctr > 60:
break
print('Alice online: ' + str(testServerAliceRunning))
print('Bob online: ' + str(testServerBobRunning))
assert ctr <= 60
time.sleep(1)
2021-08-31 18:30:39 +00:00
signingPrivateKeyPem = None
sessionClient = createSession(proxyType)
# Get Bob's instance actor
print('\n\n*********************************************************')
print("Test Bob's instance actor")
profileStr = 'https://www.w3.org/ns/activitystreams'
testHeaders = {
'host': bobAddress,
'Accept': 'application/ld+json; profile="' + profileStr + '"'
}
bobInstanceActorJson = \
getJson(signingPrivateKeyPem, sessionClient,
'http://' + bobAddress + '/@actor', testHeaders, {}, True,
2021-08-31 18:30:39 +00:00
__version__, 'http', 'somedomain.or.other', 10, True)
assert bobInstanceActorJson
pprint(bobInstanceActorJson)
assert bobInstanceActorJson['name'] == 'ACTOR'
# In the beginning all was calm and there were no follows
2021-08-05 11:24:24 +00:00
print('\n\n*********************************************************')
print("Alice and Bob agree to share items catalogs")
assert os.path.isdir(aliceDir)
assert os.path.isdir(bobDir)
setConfigParam(aliceDir, 'sharedItemsFederatedDomains', bobAddress)
setConfigParam(bobDir, 'sharedItemsFederatedDomains', aliceAddress)
print('*********************************************************')
print('Alice sends a follow request to Bob')
os.chdir(aliceDir)
sessionAlice = createSession(proxyType)
inReplyTo = None
inReplyToAtomUri = None
subject = None
alicePostLog = []
followersOnly = False
saveToFile = True
clientToServer = False
ccUrl = None
alicePersonCache = {}
aliceCachedWebfingers = {}
alicePostLog = []
bobActor = httpPrefix + '://' + bobAddress + '/users/bob'
sendResult = \
sendFollowRequest(sessionAlice, aliceDir,
'alice', aliceDomain, alicePort, httpPrefix,
'bob', bobDomain, bobActor,
bobPort, httpPrefix,
clientToServer, federationList,
aliceSendThreads, alicePostLog,
aliceCachedWebfingers, alicePersonCache,
True, __version__, signingPrivateKeyPem)
print('sendResult: ' + str(sendResult))
for t in range(16):
if os.path.isfile(bobDir + '/accounts/bob@' +
bobDomain + '/followers.txt'):
if os.path.isfile(aliceDir + '/accounts/alice@' +
aliceDomain + '/following.txt'):
if os.path.isfile(aliceDir + '/accounts/alice@' +
aliceDomain + '/followingCalendar.txt'):
break
time.sleep(1)
assert validInbox(bobDir, 'bob', bobDomain)
assert validInboxFilenames(bobDir, 'bob', bobDomain,
aliceDomain, alicePort)
assert 'alice@' + aliceDomain in open(bobDir + '/accounts/bob@' +
bobDomain + '/followers.txt').read()
assert 'bob@' + bobDomain in open(aliceDir + '/accounts/alice@' +
aliceDomain + '/following.txt').read()
assert 'bob@' + bobDomain in open(aliceDir + '/accounts/alice@' +
aliceDomain +
'/followingCalendar.txt').read()
assert not isGroupActor(aliceDir, bobActor, alicePersonCache)
assert not isGroupAccount(bobDir, 'bob', bobDomain)
print('\n\n*********************************************************')
2021-08-04 12:04:35 +00:00
print('Bob publishes some shared items')
if os.path.isdir(bobDir + '/ontology'):
shutil.rmtree(bobDir + '/ontology')
os.mkdir(bobDir + '/ontology')
2021-08-04 12:44:24 +00:00
copyfile(baseDir + '/img/logo.png', bobDir + '/logo.png')
copyfile(baseDir + '/ontology/foodTypes.json',
bobDir + '/ontology/foodTypes.json')
copyfile(baseDir + '/ontology/toolTypes.json',
bobDir + '/ontology/toolTypes.json')
copyfile(baseDir + '/ontology/clothesTypes.json',
bobDir + '/ontology/clothesTypes.json')
2021-09-07 20:33:47 +00:00
copyfile(baseDir + '/ontology/medicalTypes.json',
bobDir + '/ontology/medicalTypes.json')
copyfile(baseDir + '/ontology/accommodationTypes.json',
bobDir + '/ontology/accommodationTypes.json')
2021-08-06 16:52:12 +00:00
assert os.path.isfile(bobDir + '/logo.png')
assert os.path.isfile(bobDir + '/ontology/foodTypes.json')
assert os.path.isfile(bobDir + '/ontology/toolTypes.json')
assert os.path.isfile(bobDir + '/ontology/clothesTypes.json')
2021-09-07 20:33:47 +00:00
assert os.path.isfile(bobDir + '/ontology/medicalTypes.json')
assert os.path.isfile(bobDir + '/ontology/accommodationTypes.json')
sharedItemName = 'cheddar'
sharedItemDescription = 'Some cheese'
2021-08-04 12:44:24 +00:00
sharedItemImageFilename = 'logo.png'
sharedItemQty = 1
sharedItemType = 'Cheese'
sharedItemCategory = 'Food'
sharedItemLocation = "Bob's location"
sharedItemDuration = "10 days"
sharedItemPrice = "1.30"
sharedItemCurrency = "EUR"
signingPrivateKeyPem = None
2021-08-31 18:30:39 +00:00
sessionBob = createSession(proxyType)
shareJson = \
sendShareViaServer(bobDir, sessionBob,
'bob', bobPassword,
bobDomain, bobPort,
httpPrefix, sharedItemName,
sharedItemDescription, sharedItemImageFilename,
sharedItemQty, sharedItemType, sharedItemCategory,
sharedItemLocation, sharedItemDuration,
bobCachedWebfingers, bobPersonCache,
True, __version__,
sharedItemPrice, sharedItemCurrency,
signingPrivateKeyPem)
assert shareJson
assert isinstance(shareJson, dict)
sharedItemName = 'Epicyon T-shirt'
sharedItemDescription = 'A fashionable item'
2021-08-04 12:44:24 +00:00
sharedItemImageFilename = 'logo.png'
sharedItemQty = 1
sharedItemType = 'T-Shirt'
sharedItemCategory = 'Clothes'
sharedItemLocation = "Bob's location"
sharedItemDuration = "5 days"
sharedItemPrice = "0"
sharedItemCurrency = "EUR"
shareJson = \
sendShareViaServer(bobDir, sessionBob,
'bob', bobPassword,
bobDomain, bobPort,
httpPrefix, sharedItemName,
sharedItemDescription, sharedItemImageFilename,
sharedItemQty, sharedItemType, sharedItemCategory,
sharedItemLocation, sharedItemDuration,
bobCachedWebfingers, bobPersonCache,
True, __version__,
sharedItemPrice, sharedItemCurrency,
signingPrivateKeyPem)
assert shareJson
assert isinstance(shareJson, dict)
sharedItemName = 'Soldering iron'
sharedItemDescription = 'A soldering iron'
2021-08-04 12:44:24 +00:00
sharedItemImageFilename = 'logo.png'
sharedItemQty = 1
sharedItemType = 'Soldering iron'
sharedItemCategory = 'Tools'
sharedItemLocation = "Bob's location"
sharedItemDuration = "9 days"
sharedItemPrice = "10.00"
sharedItemCurrency = "EUR"
shareJson = \
sendShareViaServer(bobDir, sessionBob,
'bob', bobPassword,
bobDomain, bobPort,
httpPrefix, sharedItemName,
sharedItemDescription, sharedItemImageFilename,
sharedItemQty, sharedItemType, sharedItemCategory,
sharedItemLocation, sharedItemDuration,
bobCachedWebfingers, bobPersonCache,
True, __version__,
sharedItemPrice, sharedItemCurrency,
signingPrivateKeyPem)
assert shareJson
assert isinstance(shareJson, dict)
2021-08-04 12:44:24 +00:00
time.sleep(2)
2021-08-04 12:04:35 +00:00
print('\n\n*********************************************************')
2021-08-04 12:44:24 +00:00
print('Bob has a shares.json file containing the uploaded items')
2021-08-04 12:04:35 +00:00
sharesFilename = bobDir + '/accounts/bob@' + bobDomain + '/shares.json'
assert os.path.isfile(sharesFilename)
2021-08-04 12:44:24 +00:00
sharesJson = loadJson(sharesFilename)
assert sharesJson
pprint(sharesJson)
assert len(sharesJson.items()) == 3
for itemID, item in sharesJson.items():
if not item.get('dfcId'):
2021-08-06 16:52:12 +00:00
pprint(item)
print(itemID + ' does not have dfcId field')
assert item.get('dfcId')
2021-08-04 12:04:35 +00:00
print('\n\n*********************************************************')
print('Bob can read the shared items catalog on his own instance')
signingPrivateKeyPem = None
2021-08-04 12:04:35 +00:00
catalogJson = \
getSharedItemsCatalogViaServer(bobDir, sessionBob, 'bob', bobPassword,
bobDomain, bobPort, httpPrefix, True,
signingPrivateKeyPem)
2021-08-04 12:04:35 +00:00
assert catalogJson
pprint(catalogJson)
assert 'DFC:supplies' in catalogJson
assert len(catalogJson.get('DFC:supplies')) == 3
print('\n\n*********************************************************')
print('Alice sends a message to Bob')
2021-08-05 11:24:24 +00:00
aliceTokensFilename = \
aliceDir + '/accounts/sharedItemsFederationTokens.json'
assert os.path.isfile(aliceTokensFilename)
aliceSharedItemFederationTokens = loadJson(aliceTokensFilename)
assert aliceSharedItemFederationTokens
print('Alice shared item federation tokens:')
pprint(aliceSharedItemFederationTokens)
assert len(aliceSharedItemFederationTokens.items()) > 0
for hostStr, token in aliceSharedItemFederationTokens.items():
assert ':' in hostStr
alicePostLog = []
alicePersonCache = {}
aliceCachedWebfingers = {}
2021-08-05 11:24:24 +00:00
aliceSharedItemsFederatedDomains = [bobAddress]
alicePostLog = []
isArticle = False
city = 'London, England'
lowBandwidth = False
signingPrivateKeyPem = None
sendResult = \
sendPost(signingPrivateKeyPem, __version__,
sessionAlice, aliceDir, 'alice', aliceDomain, alicePort,
'bob', bobDomain, bobPort, ccUrl,
httpPrefix, 'Alice message', followersOnly, saveToFile,
clientToServer, True,
None, None, None, city, federationList,
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
2021-08-05 11:24:24 +00:00
alicePersonCache, isArticle, systemLanguage,
aliceSharedItemsFederatedDomains,
aliceSharedItemFederationTokens, lowBandwidth, True,
2021-08-05 11:24:24 +00:00
inReplyTo, inReplyToAtomUri, subject)
print('sendResult: ' + str(sendResult))
queuePath = bobDir + '/accounts/bob@' + bobDomain + '/queue'
2020-04-05 13:25:47 +00:00
inboxPath = bobDir + '/accounts/bob@' + bobDomain + '/inbox'
aliceMessageArrived = False
2019-10-15 09:31:10 +00:00
for i in range(20):
time.sleep(1)
if os.path.isdir(inboxPath):
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) > 0:
aliceMessageArrived = True
2019-10-15 09:31:10 +00:00
print('Alice message sent to Bob!')
break
2020-04-05 13:25:47 +00:00
assert aliceMessageArrived is True
2019-10-15 09:31:10 +00:00
print('Message from Alice to Bob succeeded')
2021-08-05 11:24:24 +00:00
print('\n\n*********************************************************')
print('Check that Alice received the shared items authorization')
print('token from Bob')
aliceTokensFilename = \
aliceDir + '/accounts/sharedItemsFederationTokens.json'
bobTokensFilename = \
bobDir + '/accounts/sharedItemsFederationTokens.json'
assert os.path.isfile(aliceTokensFilename)
assert os.path.isfile(bobTokensFilename)
aliceTokens = loadJson(aliceTokensFilename)
assert aliceTokens
for hostStr, token in aliceTokens.items():
assert ':' in hostStr
assert aliceTokens.get(aliceAddress)
print('Alice tokens')
pprint(aliceTokens)
bobTokens = loadJson(bobTokensFilename)
assert bobTokens
for hostStr, token in bobTokens.items():
assert ':' in hostStr
assert bobTokens.get(bobAddress)
print("Check that Bob now has Alice's token")
assert bobTokens.get(aliceAddress)
print('Bob tokens')
pprint(bobTokens)
print('\n\n*********************************************************')
print('Alice can read the federated shared items catalog of Bob')
headers = {
'Origin': aliceAddress,
'Authorization': bobTokens[bobAddress],
'host': bobAddress,
'Accept': 'application/json'
}
url = httpPrefix + '://' + bobAddress + '/catalog'
signingPrivateKeyPem = None
catalogJson = getJson(signingPrivateKeyPem, sessionAlice, url, headers,
None, True)
assert catalogJson
pprint(catalogJson)
assert 'DFC:supplies' in catalogJson
assert len(catalogJson.get('DFC:supplies')) == 3
2019-10-15 09:31:10 +00:00
# stop the servers
thrAlice.kill()
thrAlice.join()
2020-12-18 15:29:12 +00:00
assert thrAlice.is_alive() is False
2019-10-15 09:31:10 +00:00
thrBob.kill()
thrBob.join()
2020-12-18 15:29:12 +00:00
assert thrBob.is_alive() is False
2020-03-22 21:16:02 +00:00
2019-07-09 08:52:53 +00:00
# queue item removed
2019-11-09 21:39:04 +00:00
time.sleep(4)
2020-04-05 13:25:47 +00:00
assert len([name for name in os.listdir(queuePath)
if os.path.isfile(os.path.join(queuePath, name))]) == 0
2020-03-22 21:16:02 +00:00
2019-07-06 13:49:25 +00:00
os.chdir(baseDir)
2020-04-05 13:25:47 +00:00
shutil.rmtree(baseDir + '/.tests')
2021-08-04 12:04:35 +00:00
print('Testing federation of shared items between ' +
'Alice and Bob is complete')
2020-04-05 13:25:47 +00:00
2019-07-06 13:49:25 +00:00
2021-07-30 19:20:49 +00:00
def testGroupFollow():
print('Testing following of a group')
global testServerAliceRunning
2021-08-01 13:25:11 +00:00
global testServerBobRunning
2021-07-31 11:56:28 +00:00
global testServerGroupRunning
systemLanguage = 'en'
2021-07-30 19:20:49 +00:00
testServerAliceRunning = False
2021-08-01 13:25:11 +00:00
testServerBobRunning = False
2021-07-31 11:56:28 +00:00
testServerGroupRunning = False
2021-07-30 19:20:49 +00:00
# systemLanguage = 'en'
httpPrefix = 'http'
proxyType = None
federationList = []
baseDir = os.getcwd()
if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests')
os.mkdir(baseDir + '/.tests')
# create the servers
aliceDir = baseDir + '/.tests/alice'
aliceDomain = '127.0.0.57'
alicePort = 61927
aliceSendThreads = []
2021-08-01 19:19:45 +00:00
aliceAddress = aliceDomain + ':' + str(alicePort)
2021-07-30 19:20:49 +00:00
2021-08-01 13:25:11 +00:00
bobDir = baseDir + '/.tests/bob'
bobDomain = '127.0.0.59'
bobPort = 61814
bobSendThreads = []
# bobAddress = bobDomain + ':' + str(bobPort)
2021-07-30 19:20:49 +00:00
testgroupDir = baseDir + '/.tests/testgroup'
testgroupDomain = '127.0.0.63'
testgroupPort = 61925
testgroupSendThreads = []
testgroupAddress = testgroupDomain + ':' + str(testgroupPort)
global thrAlice
if thrAlice:
while thrAlice.is_alive():
thrAlice.stop()
time.sleep(1)
thrAlice.kill()
thrAlice = \
threadWithTrace(target=createServerAlice,
args=(aliceDir, aliceDomain, alicePort,
testgroupAddress,
2021-08-01 19:19:45 +00:00
federationList, False, True,
2021-07-30 19:20:49 +00:00
aliceSendThreads),
daemon=True)
2021-08-01 13:25:11 +00:00
global thrBob
if thrBob:
while thrBob.is_alive():
thrBob.stop()
time.sleep(1)
thrBob.kill()
thrBob = \
threadWithTrace(target=createServerBob,
args=(bobDir, bobDomain, bobPort, None,
federationList, False, False,
bobSendThreads),
daemon=True)
2021-07-30 19:20:49 +00:00
global thrGroup
if thrGroup:
while thrGroup.is_alive():
thrGroup.stop()
time.sleep(1)
thrGroup.kill()
thrGroup = \
threadWithTrace(target=createServerGroup,
args=(testgroupDir, testgroupDomain, testgroupPort,
federationList, False, False,
testgroupSendThreads),
daemon=True)
thrAlice.start()
2021-08-01 13:25:11 +00:00
thrBob.start()
2021-07-30 19:20:49 +00:00
thrGroup.start()
assert thrAlice.is_alive() is True
2021-08-01 13:25:11 +00:00
assert thrBob.is_alive() is True
2021-07-30 19:20:49 +00:00
assert thrGroup.is_alive() is True
# wait for all servers to be running
ctr = 0
2021-08-01 13:25:11 +00:00
while not (testServerAliceRunning and
testServerBobRunning and
testServerGroupRunning):
2021-07-30 19:20:49 +00:00
time.sleep(1)
ctr += 1
if ctr > 60:
break
print('Alice online: ' + str(testServerAliceRunning))
2021-08-01 13:25:11 +00:00
print('Bob online: ' + str(testServerBobRunning))
2021-07-30 19:20:49 +00:00
print('Test Group online: ' + str(testServerGroupRunning))
assert ctr <= 60
time.sleep(1)
2021-08-01 19:19:45 +00:00
print('*********************************************************')
print('Alice has some outbox posts')
aliceOutbox = 'http://' + aliceAddress + '/users/alice/outbox'
session = createSession(None)
profileStr = 'https://www.w3.org/ns/activitystreams'
asHeader = {
'Accept': 'application/ld+json; profile="' + profileStr + '"'
}
signingPrivateKeyPem = None
outboxJson = getJson(signingPrivateKeyPem, session, aliceOutbox, asHeader,
None, True, __version__, 'http', None)
2021-08-01 19:19:45 +00:00
assert outboxJson
pprint(outboxJson)
assert outboxJson['type'] == 'OrderedCollection'
assert 'first' in outboxJson
firstPage = outboxJson['first']
assert 'totalItems' in outboxJson
print('Alice outbox totalItems: ' + str(outboxJson['totalItems']))
assert outboxJson['totalItems'] == 3
outboxJson = getJson(signingPrivateKeyPem, session, firstPage, asHeader,
None, True, __version__, 'http', None)
2021-08-01 19:19:45 +00:00
assert outboxJson
pprint(outboxJson)
assert 'orderedItems' in outboxJson
assert outboxJson['type'] == 'OrderedCollectionPage'
print('Alice outbox orderedItems: ' +
str(len(outboxJson['orderedItems'])))
assert len(outboxJson['orderedItems']) == 3
2021-07-30 19:20:49 +00:00
queuePath = \
testgroupDir + '/accounts/testgroup@' + testgroupDomain + '/queue'
# In the beginning the test group had no followers
print('*********************************************************')
print('Alice sends a follow request to the test group')
os.chdir(aliceDir)
sessionAlice = createSession(proxyType)
2021-07-31 11:56:28 +00:00
inReplyTo = None
inReplyToAtomUri = None
subject = None
2021-07-30 19:20:49 +00:00
alicePostLog = []
2021-07-31 11:56:28 +00:00
followersOnly = False
saveToFile = True
2021-07-30 19:20:49 +00:00
clientToServer = False
2021-07-31 11:56:28 +00:00
ccUrl = None
2021-07-30 19:20:49 +00:00
alicePersonCache = {}
aliceCachedWebfingers = {}
alicePostLog = []
2021-07-31 11:56:28 +00:00
# aliceActor = httpPrefix + '://' + aliceAddress + '/users/alice'
2021-07-30 19:20:49 +00:00
testgroupActor = httpPrefix + '://' + testgroupAddress + '/users/testgroup'
signingPrivateKeyPem = None
2021-07-30 19:20:49 +00:00
sendResult = \
sendFollowRequest(sessionAlice, aliceDir,
'alice', aliceDomain, alicePort, httpPrefix,
'testgroup', testgroupDomain, testgroupActor,
testgroupPort, httpPrefix,
clientToServer, federationList,
aliceSendThreads, alicePostLog,
aliceCachedWebfingers, alicePersonCache,
True, __version__, signingPrivateKeyPem)
2021-07-30 19:20:49 +00:00
print('sendResult: ' + str(sendResult))
2021-07-31 11:56:28 +00:00
aliceFollowingFilename = \
aliceDir + '/accounts/alice@' + aliceDomain + '/following.txt'
aliceFollowingCalendarFilename = \
aliceDir + '/accounts/alice@' + aliceDomain + \
'/followingCalendar.txt'
testgroupFollowersFilename = \
testgroupDir + '/accounts/testgroup@' + testgroupDomain + \
'/followers.txt'
2021-07-30 19:20:49 +00:00
for t in range(16):
2021-07-31 11:56:28 +00:00
if os.path.isfile(testgroupFollowersFilename):
if os.path.isfile(aliceFollowingFilename):
if os.path.isfile(aliceFollowingCalendarFilename):
2021-07-30 19:20:49 +00:00
break
time.sleep(1)
assert validInbox(testgroupDir, 'testgroup', testgroupDomain)
assert validInboxFilenames(testgroupDir, 'testgroup', testgroupDomain,
aliceDomain, alicePort)
2021-07-31 11:56:28 +00:00
assert 'alice@' + aliceDomain in open(testgroupFollowersFilename).read()
2021-08-01 16:23:32 +00:00
assert '!alice@' + aliceDomain not in \
open(testgroupFollowersFilename).read()
2021-07-31 11:56:28 +00:00
testgroupWebfingerFilename = \
testgroupDir + '/wfendpoints/testgroup@' + \
testgroupDomain + ':' + str(testgroupPort) + '.json'
assert os.path.isfile(testgroupWebfingerFilename)
assert 'group:testgroup@' in open(testgroupWebfingerFilename).read()
print('group: exists within the webfinger endpoint for testgroup')
2021-07-30 19:20:49 +00:00
testgroupHandle = 'testgroup@' + testgroupDomain
2021-07-31 11:56:28 +00:00
followingStr = ''
with open(aliceFollowingFilename, 'r') as fp:
followingStr = fp.read()
print('Alice following.txt:\n\n' + followingStr)
if '!testgroup' not in followingStr:
print('Alice following.txt does not contain !testgroup@' +
testgroupDomain + ':' + str(testgroupPort))
assert isGroupActor(aliceDir, testgroupActor, alicePersonCache)
assert not isGroupAccount(aliceDir, 'alice', aliceDomain)
assert isGroupAccount(testgroupDir, 'testgroup', testgroupDomain)
2021-07-31 11:56:28 +00:00
assert '!testgroup' in followingStr
assert testgroupHandle in open(aliceFollowingFilename).read()
assert testgroupHandle in open(aliceFollowingCalendarFilename).read()
2021-08-01 13:25:11 +00:00
print('\n\n*********************************************************')
2021-07-31 11:56:28 +00:00
print('Alice follows the test group')
2021-08-01 13:25:11 +00:00
print('*********************************************************')
print('Bob sends a follow request to the test group')
os.chdir(bobDir)
sessionBob = createSession(proxyType)
inReplyTo = None
inReplyToAtomUri = None
subject = None
bobPostLog = []
followersOnly = False
saveToFile = True
clientToServer = False
ccUrl = None
bobPersonCache = {}
bobCachedWebfingers = {}
bobPostLog = []
# bobActor = httpPrefix + '://' + bobAddress + '/users/bob'
testgroupActor = httpPrefix + '://' + testgroupAddress + '/users/testgroup'
signingPrivateKeyPem = None
2021-08-01 13:25:11 +00:00
sendResult = \
sendFollowRequest(sessionBob, bobDir,
'bob', bobDomain, bobPort, httpPrefix,
'testgroup', testgroupDomain, testgroupActor,
testgroupPort, httpPrefix,
clientToServer, federationList,
bobSendThreads, bobPostLog,
bobCachedWebfingers, bobPersonCache,
True, __version__, signingPrivateKeyPem)
2021-08-01 13:25:11 +00:00
print('sendResult: ' + str(sendResult))
bobFollowingFilename = \
bobDir + '/accounts/bob@' + bobDomain + '/following.txt'
bobFollowingCalendarFilename = \
bobDir + '/accounts/bob@' + bobDomain + \
'/followingCalendar.txt'
testgroupFollowersFilename = \
testgroupDir + '/accounts/testgroup@' + testgroupDomain + \
'/followers.txt'
for t in range(16):
if os.path.isfile(testgroupFollowersFilename):
if os.path.isfile(bobFollowingFilename):
if os.path.isfile(bobFollowingCalendarFilename):
break
time.sleep(1)
assert validInbox(testgroupDir, 'testgroup', testgroupDomain)
assert validInboxFilenames(testgroupDir, 'testgroup', testgroupDomain,
bobDomain, bobPort)
assert 'bob@' + bobDomain in open(testgroupFollowersFilename).read()
assert '!bob@' + bobDomain not in open(testgroupFollowersFilename).read()
testgroupWebfingerFilename = \
testgroupDir + '/wfendpoints/testgroup@' + \
testgroupDomain + ':' + str(testgroupPort) + '.json'
assert os.path.isfile(testgroupWebfingerFilename)
assert 'group:testgroup@' in open(testgroupWebfingerFilename).read()
print('group: exists within the webfinger endpoint for testgroup')
testgroupHandle = 'testgroup@' + testgroupDomain
followingStr = ''
with open(bobFollowingFilename, 'r') as fp:
followingStr = fp.read()
print('Bob following.txt:\n\n' + followingStr)
if '!testgroup' not in followingStr:
print('Bob following.txt does not contain !testgroup@' +
testgroupDomain + ':' + str(testgroupPort))
assert isGroupActor(bobDir, testgroupActor, bobPersonCache)
assert '!testgroup' in followingStr
assert testgroupHandle in open(bobFollowingFilename).read()
assert testgroupHandle in open(bobFollowingCalendarFilename).read()
print('Bob follows the test group')
2021-07-31 11:56:28 +00:00
print('\n\n*********************************************************')
print('Alice posts to the test group')
2021-08-01 13:25:11 +00:00
inboxPathBob = \
2021-08-01 16:23:32 +00:00
bobDir + '/accounts/bob@' + bobDomain + '/inbox'
2021-08-01 13:25:11 +00:00
startPostsBob = \
len([name for name in os.listdir(inboxPathBob)
if os.path.isfile(os.path.join(inboxPathBob, name))])
assert startPostsBob == 0
2021-07-31 11:56:28 +00:00
alicePostLog = []
alicePersonCache = {}
aliceCachedWebfingers = {}
2021-08-05 11:24:24 +00:00
aliceSharedItemsFederatedDomains = []
aliceSharedItemFederationTokens = {}
2021-07-31 11:56:28 +00:00
alicePostLog = []
isArticle = False
city = 'London, England'
lowBandwidth = False
signingPrivateKeyPem = None
2021-07-31 11:56:28 +00:00
sendResult = \
sendPost(signingPrivateKeyPem, __version__,
2021-07-31 11:56:28 +00:00
sessionAlice, aliceDir, 'alice', aliceDomain, alicePort,
'testgroup', testgroupDomain, testgroupPort, ccUrl,
httpPrefix, "Alice group message", followersOnly,
saveToFile, clientToServer, True,
None, None, None, city, federationList,
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
2021-08-05 11:24:24 +00:00
alicePersonCache, isArticle, systemLanguage,
aliceSharedItemsFederatedDomains,
aliceSharedItemFederationTokens, lowBandwidth,
2021-08-05 11:24:24 +00:00
inReplyTo, inReplyToAtomUri, subject)
2021-07-31 11:56:28 +00:00
print('sendResult: ' + str(sendResult))
queuePath = \
testgroupDir + '/accounts/testgroup@' + testgroupDomain + '/queue'
inboxPath = \
testgroupDir + '/accounts/testgroup@' + testgroupDomain + '/inbox'
aliceMessageArrived = False
startPosts = len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
for i in range(20):
time.sleep(1)
if os.path.isdir(inboxPath):
currPosts = \
len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
if currPosts > startPosts:
aliceMessageArrived = True
print('Alice post sent to test group!')
break
assert aliceMessageArrived is True
2021-08-01 13:25:11 +00:00
print('\n\n*********************************************************')
2021-07-31 11:56:28 +00:00
print('Post from Alice to test group succeeded')
2021-08-01 19:19:45 +00:00
2021-08-01 13:25:11 +00:00
print('\n\n*********************************************************')
print('Check that post was relayed from test group to bob')
2021-08-02 14:19:09 +00:00
bobMessageArrived = False
2021-08-01 13:25:11 +00:00
for i in range(20):
time.sleep(1)
if os.path.isdir(inboxPathBob):
currPostsBob = \
len([name for name in os.listdir(inboxPathBob)
if os.path.isfile(os.path.join(inboxPathBob, name))])
if currPostsBob > startPostsBob:
2021-08-02 14:19:09 +00:00
bobMessageArrived = True
2021-08-01 13:25:11 +00:00
print('Bob received relayed group post!')
break
2021-08-02 14:19:09 +00:00
assert bobMessageArrived is True
2021-07-30 19:20:49 +00:00
# stop the servers
thrAlice.kill()
thrAlice.join()
assert thrAlice.is_alive() is False
2021-08-01 13:25:11 +00:00
thrBob.kill()
thrBob.join()
assert thrBob.is_alive() is False
2021-07-30 19:20:49 +00:00
thrGroup.kill()
thrGroup.join()
assert thrGroup.is_alive() is False
# queue item removed
time.sleep(4)
assert len([name for name in os.listdir(queuePath)
if os.path.isfile(os.path.join(queuePath, name))]) == 0
os.chdir(baseDir)
shutil.rmtree(baseDir + '/.tests')
2021-07-31 11:56:28 +00:00
print('Testing following of a group is complete')
2021-07-30 19:20:49 +00:00
def _testFollowersOfPerson():
print('testFollowersOfPerson')
2020-04-05 13:25:47 +00:00
currDir = os.getcwd()
nickname = 'mxpop'
domain = 'diva.domain'
password = 'birb'
port = 80
httpPrefix = 'https'
federationList = []
baseDir = currDir + '/.tests_followersofperson'
if os.path.isdir(baseDir):
shutil.rmtree(baseDir)
os.mkdir(baseDir)
2020-03-22 21:16:02 +00:00
os.chdir(baseDir)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, nickname, domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'maxboardroom', domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'ultrapancake', domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'drokk', domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'sausagedog', domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
clearFollows(baseDir, nickname, domain)
followPerson(baseDir, nickname, domain, 'maxboardroom', domain,
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followPerson(baseDir, 'drokk', domain, 'ultrapancake', domain,
2021-07-30 16:06:34 +00:00
federationList, False, False)
# deliberate duplication
2020-04-05 13:25:47 +00:00
followPerson(baseDir, 'drokk', domain, 'ultrapancake', domain,
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followPerson(baseDir, 'sausagedog', domain, 'ultrapancake', domain,
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followPerson(baseDir, nickname, domain, 'ultrapancake', domain,
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followPerson(baseDir, nickname, domain, 'someother', 'randodomain.net',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followList = getFollowersOfPerson(baseDir, 'ultrapancake', domain)
assert len(followList) == 3
assert 'mxpop@' + domain in followList
assert 'drokk@' + domain in followList
assert 'sausagedog@' + domain in followList
os.chdir(currDir)
shutil.rmtree(baseDir)
2020-04-05 13:25:47 +00:00
def _testNoOfFollowersOnDomain():
print('testNoOfFollowersOnDomain')
2020-04-05 13:25:47 +00:00
currDir = os.getcwd()
nickname = 'mxpop'
domain = 'diva.domain'
otherdomain = 'soup.dragon'
password = 'birb'
port = 80
httpPrefix = 'https'
federationList = []
baseDir = currDir + '/.tests_nooffollowersOndomain'
if os.path.isdir(baseDir):
shutil.rmtree(baseDir)
os.mkdir(baseDir)
2020-03-22 21:16:02 +00:00
os.chdir(baseDir)
2020-07-12 12:31:28 +00:00
createPerson(baseDir, nickname, domain, port, httpPrefix, True,
False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'maxboardroom', otherdomain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'ultrapancake', otherdomain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'drokk', otherdomain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'sausagedog', otherdomain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
followPerson(baseDir, 'drokk', otherdomain, nickname, domain,
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followPerson(baseDir, 'sausagedog', otherdomain, nickname, domain,
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followPerson(baseDir, 'maxboardroom', otherdomain, nickname, domain,
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain,
'cucumber', 'sandwiches.party',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain,
'captainsensible', 'damned.zone',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain, 'pilchard', 'zombies.attack',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain, 'drokk', otherdomain,
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain, 'sausagedog', otherdomain,
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain, 'maxboardroom', otherdomain,
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followersOnOtherDomain = \
noOfFollowersOnDomain(baseDir, nickname + '@' + domain, otherdomain)
assert followersOnOtherDomain == 3
2021-07-30 16:06:34 +00:00
unfollowerOfAccount(baseDir, nickname, domain, 'sausagedog', otherdomain,
False, False)
2020-04-05 13:25:47 +00:00
followersOnOtherDomain = \
noOfFollowersOnDomain(baseDir, nickname + '@' + domain, otherdomain)
assert followersOnOtherDomain == 2
2020-03-22 21:16:02 +00:00
os.chdir(currDir)
shutil.rmtree(baseDir)
2020-04-05 13:25:47 +00:00
def _testGroupFollowers():
print('testGroupFollowers')
2020-04-05 13:25:47 +00:00
currDir = os.getcwd()
nickname = 'test735'
domain = 'mydomain.com'
password = 'somepass'
port = 80
httpPrefix = 'https'
federationList = []
baseDir = currDir + '/.tests_testgroupfollowers'
if os.path.isdir(baseDir):
shutil.rmtree(baseDir)
os.mkdir(baseDir)
2020-03-22 21:16:02 +00:00
os.chdir(baseDir)
2020-07-12 12:31:28 +00:00
createPerson(baseDir, nickname, domain, port, httpPrefix, True,
False, password)
2020-04-05 13:25:47 +00:00
clearFollowers(baseDir, nickname, domain)
followerOfPerson(baseDir, nickname, domain, 'badger', 'wild.domain',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain, 'squirrel', 'wild.domain',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain, 'rodent', 'wild.domain',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain, 'utterly', 'clutterly.domain',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain, 'zonked', 'zzz.domain',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain, 'nap', 'zzz.domain',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
grouped = groupFollowersByDomain(baseDir, nickname, domain)
assert len(grouped.items()) == 3
assert grouped.get('zzz.domain')
assert grouped.get('clutterly.domain')
assert grouped.get('wild.domain')
2020-04-05 13:25:47 +00:00
assert len(grouped['zzz.domain']) == 2
assert len(grouped['wild.domain']) == 3
assert len(grouped['clutterly.domain']) == 1
2020-03-22 21:16:02 +00:00
os.chdir(currDir)
shutil.rmtree(baseDir)
2020-03-22 21:16:02 +00:00
def _testFollows():
2019-07-03 10:04:23 +00:00
print('testFollows')
2020-04-05 13:25:47 +00:00
currDir = os.getcwd()
nickname = 'test529'
domain = 'testdomain.com'
password = 'mypass'
port = 80
httpPrefix = 'https'
federationList = ['wild.com', 'mesh.com']
baseDir = currDir + '/.tests_testfollows'
2019-07-03 09:24:55 +00:00
if os.path.isdir(baseDir):
shutil.rmtree(baseDir)
os.mkdir(baseDir)
2020-03-22 21:16:02 +00:00
os.chdir(baseDir)
2020-07-12 12:31:28 +00:00
createPerson(baseDir, nickname, domain, port, httpPrefix, True,
False, password)
2020-04-05 13:25:47 +00:00
clearFollows(baseDir, nickname, domain)
followPerson(baseDir, nickname, domain, 'badger', 'wild.com',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followPerson(baseDir, nickname, domain, 'squirrel', 'secret.com',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followPerson(baseDir, nickname, domain, 'rodent', 'drainpipe.com',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followPerson(baseDir, nickname, domain, 'batman', 'mesh.com',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followPerson(baseDir, nickname, domain, 'giraffe', 'trees.com',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
2021-07-13 21:59:53 +00:00
accountDir = acctDir(baseDir, nickname, domain)
f = open(accountDir + '/following.txt', 'r')
2020-04-05 13:25:47 +00:00
domainFound = False
2019-07-03 09:24:55 +00:00
for followingDomain in f:
2020-05-22 11:32:38 +00:00
testDomain = followingDomain.split('@')[1]
testDomain = testDomain.replace('\n', '').replace('\r', '')
2020-04-05 13:25:47 +00:00
if testDomain == 'mesh.com':
domainFound = True
2019-07-03 09:24:55 +00:00
if testDomain not in federationList:
print(testDomain)
assert(False)
2019-07-03 09:33:28 +00:00
assert(domainFound)
2021-07-30 16:06:34 +00:00
unfollowAccount(baseDir, nickname, domain, 'batman', 'mesh.com',
True, False)
2019-07-03 09:33:28 +00:00
2020-04-05 13:25:47 +00:00
domainFound = False
2019-07-03 09:33:28 +00:00
for followingDomain in f:
2020-05-22 11:32:38 +00:00
testDomain = followingDomain.split('@')[1]
testDomain = testDomain.replace('\n', '').replace('\r', '')
2020-04-05 13:25:47 +00:00
if testDomain == 'mesh.com':
domainFound = True
assert(domainFound is False)
clearFollowers(baseDir, nickname, domain)
followerOfPerson(baseDir, nickname, domain, 'badger', 'wild.com',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain, 'squirrel', 'secret.com',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain, 'rodent', 'drainpipe.com',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain, 'batman', 'mesh.com',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
followerOfPerson(baseDir, nickname, domain, 'giraffe', 'trees.com',
2021-07-30 16:06:34 +00:00
federationList, False, False)
2020-04-05 13:25:47 +00:00
2021-07-13 21:59:53 +00:00
accountDir = acctDir(baseDir, nickname, domain)
f = open(accountDir + '/followers.txt', 'r')
2019-07-03 09:24:55 +00:00
for followerDomain in f:
2020-05-22 11:32:38 +00:00
testDomain = followerDomain.split('@')[1]
testDomain = testDomain.replace('\n', '').replace('\r', '')
2019-07-03 09:24:55 +00:00
if testDomain not in federationList:
print(testDomain)
assert(False)
os.chdir(currDir)
shutil.rmtree(baseDir)
2019-07-03 10:04:23 +00:00
2020-04-05 13:25:47 +00:00
def _testCreatePerson():
2019-07-03 10:04:23 +00:00
print('testCreatePerson')
2021-07-18 09:55:49 +00:00
systemLanguage = 'en'
2020-04-05 13:25:47 +00:00
currDir = os.getcwd()
nickname = 'test382'
domain = 'badgerdomain.com'
password = 'mypass'
port = 80
httpPrefix = 'https'
clientToServer = False
baseDir = currDir + '/.tests_createperson'
2019-07-03 10:04:23 +00:00
if os.path.isdir(baseDir):
shutil.rmtree(baseDir)
os.mkdir(baseDir)
os.chdir(baseDir)
2020-03-22 21:16:02 +00:00
2020-04-05 13:25:47 +00:00
privateKeyPem, publicKeyPem, person, wfEndpoint = \
createPerson(baseDir, nickname, domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
assert os.path.isfile(baseDir + '/accounts/passwords')
deleteAllPosts(baseDir, nickname, domain, 'inbox')
deleteAllPosts(baseDir, nickname, domain, 'outbox')
setDisplayNickname(baseDir, nickname, domain, 'badger')
setBio(baseDir, nickname, domain, 'Randomly roaming in your backyard')
archivePostsForPerson(nickname, domain, baseDir, 'inbox', None, {}, 4)
archivePostsForPerson(nickname, domain, baseDir, 'outbox', None, {}, 4)
2021-07-01 20:41:17 +00:00
testInReplyTo = None
testInReplyToAtomUri = None
testSubject = None
testSchedulePost = False
testEventDate = None
testEventTime = None
testLocation = None
testIsArticle = False
content = "G'day world!"
followersOnly = False
saveToFile = True
commentsEnabled = True
attachImageFilename = None
mediaType = None
2021-08-08 16:52:32 +00:00
conversationId = None
lowBandwidth = True
2020-04-05 13:25:47 +00:00
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
2021-07-01 20:41:17 +00:00
content, followersOnly, saveToFile, clientToServer,
commentsEnabled, attachImageFilename, mediaType,
'Not suitable for Vogons', 'London, England',
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId,
lowBandwidth)
2019-07-03 10:04:23 +00:00
os.chdir(currDir)
shutil.rmtree(baseDir)
2020-04-05 13:25:47 +00:00
2021-08-20 11:22:20 +00:00
def showTestBoxes(name: str, inboxPath: str, outboxPath: str) -> None:
inboxPosts = \
len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
outboxPosts = \
len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))])
print('EVENT: ' + name +
' inbox has ' + str(inboxPosts) + ' posts and ' +
str(outboxPosts) + ' outbox posts')
def _testAuthentication():
2019-07-03 18:24:44 +00:00
print('testAuthentication')
2020-04-05 13:25:47 +00:00
currDir = os.getcwd()
nickname = 'test8743'
password = 'SuperSecretPassword12345'
2019-07-03 18:24:44 +00:00
2020-04-05 13:25:47 +00:00
baseDir = currDir + '/.tests_authentication'
2019-07-03 18:24:44 +00:00
if os.path.isdir(baseDir):
shutil.rmtree(baseDir)
os.mkdir(baseDir)
os.chdir(baseDir)
2020-04-05 13:25:47 +00:00
assert storeBasicCredentials(baseDir, 'othernick', 'otherpass')
assert storeBasicCredentials(baseDir, 'bad:nick', 'otherpass') is False
assert storeBasicCredentials(baseDir, 'badnick', 'otherpa:ss') is False
assert storeBasicCredentials(baseDir, nickname, password)
2019-07-03 18:24:44 +00:00
2020-04-05 13:25:47 +00:00
authHeader = createBasicAuthHeader(nickname, password)
assert authorizeBasic(baseDir, '/users/' + nickname + '/inbox',
authHeader, False)
assert authorizeBasic(baseDir, '/users/' + nickname,
authHeader, False) is False
assert authorizeBasic(baseDir, '/users/othernick/inbox',
authHeader, False) is False
2019-07-03 18:24:44 +00:00
2020-04-05 13:25:47 +00:00
authHeader = createBasicAuthHeader(nickname, password + '1')
assert authorizeBasic(baseDir, '/users/' + nickname + '/inbox',
authHeader, False) is False
2019-07-03 18:24:44 +00:00
2020-04-05 13:25:47 +00:00
password = 'someOtherPassword'
assert storeBasicCredentials(baseDir, nickname, password)
2019-07-03 19:13:23 +00:00
2020-04-05 13:25:47 +00:00
authHeader = createBasicAuthHeader(nickname, password)
assert authorizeBasic(baseDir, '/users/' + nickname + '/inbox',
authHeader, False)
2019-07-03 19:13:23 +00:00
2019-07-03 18:24:44 +00:00
os.chdir(currDir)
shutil.rmtree(baseDir)
2019-07-16 10:19:04 +00:00
2020-04-05 13:25:47 +00:00
2019-07-16 10:19:04 +00:00
def testClientToServer():
2021-08-20 11:22:20 +00:00
print('EVENT: Testing sending a post via c2s')
2019-07-16 10:19:04 +00:00
global testServerAliceRunning
global testServerBobRunning
2020-04-05 13:25:47 +00:00
testServerAliceRunning = False
testServerBobRunning = False
2019-07-16 10:19:04 +00:00
2021-07-18 09:55:49 +00:00
systemLanguage = 'en'
2020-04-05 13:25:47 +00:00
httpPrefix = 'http'
2020-06-09 11:03:59 +00:00
proxyType = None
2020-04-05 13:25:47 +00:00
federationList = []
lowBandwidth = False
2019-07-16 10:19:04 +00:00
2020-04-05 13:25:47 +00:00
baseDir = os.getcwd()
if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests')
os.mkdir(baseDir + '/.tests')
2019-07-16 10:19:04 +00:00
# create the servers
2020-04-05 13:25:47 +00:00
aliceDir = baseDir + '/.tests/alice'
aliceDomain = '127.0.0.42'
alicePort = 61935
aliceSendThreads = []
aliceAddress = aliceDomain + ':' + str(alicePort)
bobDir = baseDir + '/.tests/bob'
bobDomain = '127.0.0.64'
bobPort = 61936
bobSendThreads = []
bobAddress = bobDomain + ':' + str(bobPort)
2020-02-19 12:27:21 +00:00
global thrAlice
if thrAlice:
2020-12-18 15:29:12 +00:00
while thrAlice.is_alive():
2020-02-19 12:27:21 +00:00
thrAlice.stop()
time.sleep(1)
thrAlice.kill()
2020-04-05 13:25:47 +00:00
thrAlice = \
threadWithTrace(target=createServerAlice,
args=(aliceDir, aliceDomain, alicePort, bobAddress,
federationList, False, False,
2020-09-27 19:27:24 +00:00
aliceSendThreads),
2020-04-05 13:25:47 +00:00
daemon=True)
2020-03-22 21:16:02 +00:00
2020-02-19 12:27:21 +00:00
global thrBob
if thrBob:
2020-12-18 15:29:12 +00:00
while thrBob.is_alive():
2020-02-19 12:27:21 +00:00
thrBob.stop()
time.sleep(1)
thrBob.kill()
2020-04-05 13:25:47 +00:00
thrBob = \
threadWithTrace(target=createServerBob,
args=(bobDir, bobDomain, bobPort, aliceAddress,
federationList, False, False,
2020-09-27 19:27:24 +00:00
bobSendThreads),
2020-04-05 13:25:47 +00:00
daemon=True)
2019-07-16 10:19:04 +00:00
thrAlice.start()
thrBob.start()
2020-12-18 15:29:12 +00:00
assert thrAlice.is_alive() is True
assert thrBob.is_alive() is True
2019-07-16 10:19:04 +00:00
# wait for both servers to be running
2020-04-05 13:25:47 +00:00
ctr = 0
2019-07-16 10:19:04 +00:00
while not (testServerAliceRunning and testServerBobRunning):
time.sleep(1)
2020-04-05 13:25:47 +00:00
ctr += 1
if ctr > 60:
2019-07-16 10:19:04 +00:00
break
2020-04-05 13:25:47 +00:00
print('Alice online: ' + str(testServerAliceRunning))
print('Bob online: ' + str(testServerBobRunning))
2019-07-16 10:19:04 +00:00
time.sleep(1)
2020-03-22 21:16:02 +00:00
2019-07-16 10:19:04 +00:00
print('\n\n*******************************************************')
2021-08-20 11:22:20 +00:00
print('EVENT: Alice sends to Bob via c2s')
2019-07-16 10:19:04 +00:00
2020-06-09 11:03:59 +00:00
sessionAlice = createSession(proxyType)
2020-04-05 13:25:47 +00:00
followersOnly = False
2021-03-17 20:18:00 +00:00
attachedImageFilename = baseDir + '/img/logo.png'
2020-04-05 13:25:47 +00:00
mediaType = getAttachmentMediaType(attachedImageFilename)
attachedImageDescription = 'Logo'
2021-05-09 19:29:53 +00:00
city = 'London, England'
2020-04-05 13:25:47 +00:00
isArticle = False
cachedWebfingers = {}
personCache = {}
password = 'alicepass'
2021-08-08 16:52:32 +00:00
conversationId = None
2021-08-20 11:22:20 +00:00
aliceInboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/inbox'
aliceOutboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox'
bobInboxPath = bobDir + '/accounts/bob@' + bobDomain + '/inbox'
bobOutboxPath = bobDir + '/accounts/bob@' + bobDomain + '/outbox'
2020-04-05 13:25:47 +00:00
outboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox'
inboxPath = bobDir + '/accounts/bob@' + bobDomain + '/inbox'
2021-08-20 11:22:20 +00:00
showTestBoxes('alice', aliceInboxPath, aliceOutboxPath)
showTestBoxes('bob', bobInboxPath, bobOutboxPath)
assert len([name for name in os.listdir(aliceInboxPath)
if os.path.isfile(os.path.join(aliceInboxPath, name))]) == 0
assert len([name for name in os.listdir(aliceOutboxPath)
if os.path.isfile(os.path.join(aliceOutboxPath, name))]) == 0
assert len([name for name in os.listdir(bobInboxPath)
if os.path.isfile(os.path.join(bobInboxPath, name))]) == 0
assert len([name for name in os.listdir(bobOutboxPath)
if os.path.isfile(os.path.join(bobOutboxPath, name))]) == 0
print('EVENT: all inboxes and outboxes are empty')
signingPrivateKeyPem = None
2020-04-05 13:25:47 +00:00
sendResult = \
sendPostViaServer(signingPrivateKeyPem, __version__,
2020-04-05 13:25:47 +00:00
aliceDir, sessionAlice, 'alice', password,
aliceDomain, alicePort,
'bob', bobDomain, bobPort, None,
httpPrefix, 'Sent from my ActivityPub client',
2020-08-21 17:40:50 +00:00
followersOnly, True,
2020-04-05 13:25:47 +00:00
attachedImageFilename, mediaType,
2021-05-09 19:11:05 +00:00
attachedImageDescription, city,
2020-04-05 13:25:47 +00:00
cachedWebfingers, personCache, isArticle,
systemLanguage, lowBandwidth,
True, None, None,
2021-08-08 16:52:32 +00:00
conversationId, None)
2020-04-05 13:25:47 +00:00
print('sendResult: ' + str(sendResult))
2019-07-16 10:19:04 +00:00
for i in range(30):
if os.path.isdir(outboxPath):
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 1:
2019-07-16 10:19:04 +00:00
break
time.sleep(1)
2019-07-16 11:33:40 +00:00
2021-08-20 11:22:20 +00:00
showTestBoxes('alice', aliceInboxPath, aliceOutboxPath)
showTestBoxes('bob', bobInboxPath, bobOutboxPath)
assert len([name for name in os.listdir(aliceInboxPath)
if os.path.isfile(os.path.join(aliceInboxPath, name))]) == 0
assert len([name for name in os.listdir(aliceOutboxPath)
if os.path.isfile(os.path.join(aliceOutboxPath, name))]) == 1
print(">>> c2s post arrived in Alice's outbox\n\n\n")
2020-03-22 21:16:02 +00:00
2019-07-16 11:33:40 +00:00
for i in range(30):
if os.path.isdir(inboxPath):
2021-08-20 11:22:20 +00:00
if len([name for name in os.listdir(bobInboxPath)
if os.path.isfile(os.path.join(bobInboxPath, name))]) == 1:
2019-07-16 11:33:40 +00:00
break
time.sleep(1)
2021-08-20 11:22:20 +00:00
showTestBoxes('alice', aliceInboxPath, aliceOutboxPath)
showTestBoxes('bob', bobInboxPath, bobOutboxPath)
assert len([name for name in os.listdir(bobInboxPath)
if os.path.isfile(os.path.join(bobInboxPath, name))]) == 1
assert len([name for name in os.listdir(bobOutboxPath)
if os.path.isfile(os.path.join(bobOutboxPath, name))]) == 0
2019-07-16 11:33:40 +00:00
print(">>> s2s post arrived in Bob's inbox")
2021-08-20 11:22:20 +00:00
print("c2s send success\n\n\n")
2019-07-16 11:33:40 +00:00
2021-08-20 11:22:20 +00:00
print('\n\nEVENT: Getting message id for the post')
2020-04-05 13:25:47 +00:00
statusNumber = 0
outboxPostFilename = None
outboxPostId = None
2019-07-16 19:07:45 +00:00
for name in os.listdir(outboxPath):
if '#statuses#' in name:
2020-04-05 13:25:47 +00:00
statusNumber = name.split('#statuses#')[1].replace('.json', '')
statusNumber = int(statusNumber.replace('#activity', ''))
outboxPostFilename = outboxPath + '/' + name
postJsonObject = loadJson(outboxPostFilename, 0)
if postJsonObject:
2020-08-23 11:13:35 +00:00
outboxPostId = removeIdEnding(postJsonObject['id'])
2019-07-16 19:07:45 +00:00
assert outboxPostId
2020-04-05 13:25:47 +00:00
print('message id obtained: ' + outboxPostId)
assert validInbox(bobDir, 'bob', bobDomain)
assert validInboxFilenames(bobDir, 'bob', bobDomain,
aliceDomain, alicePort)
2019-07-16 21:38:06 +00:00
print('\n\nAlice follows Bob')
signingPrivateKeyPem = None
2020-04-05 13:25:47 +00:00
sendFollowRequestViaServer(aliceDir, sessionAlice,
'alice', password,
aliceDomain, alicePort,
'bob', bobDomain, bobPort,
httpPrefix,
cachedWebfingers, personCache,
True, __version__, signingPrivateKeyPem)
2020-11-23 15:07:55 +00:00
alicePetnamesFilename = aliceDir + '/accounts/' + \
'alice@' + aliceDomain + '/petnames.txt'
2020-04-05 13:25:47 +00:00
aliceFollowingFilename = \
aliceDir + '/accounts/alice@' + aliceDomain + '/following.txt'
bobFollowersFilename = \
bobDir + '/accounts/bob@' + bobDomain + '/followers.txt'
2020-03-02 21:28:22 +00:00
for t in range(10):
if os.path.isfile(bobFollowersFilename):
2020-04-05 13:25:47 +00:00
if 'alice@' + aliceDomain + ':' + str(alicePort) in \
open(bobFollowersFilename).read():
2020-11-23 15:07:55 +00:00
if os.path.isfile(aliceFollowingFilename) and \
os.path.isfile(alicePetnamesFilename):
2020-04-05 13:25:47 +00:00
if 'bob@' + bobDomain + ':' + str(bobPort) in \
open(aliceFollowingFilename).read():
2019-07-17 11:24:11 +00:00
break
2019-07-16 21:38:06 +00:00
time.sleep(1)
2020-03-02 21:28:22 +00:00
assert os.path.isfile(bobFollowersFilename)
assert os.path.isfile(aliceFollowingFilename)
2020-11-23 15:07:55 +00:00
assert os.path.isfile(alicePetnamesFilename)
assert 'bob bob@' + bobDomain in \
open(alicePetnamesFilename).read()
2020-04-05 13:25:47 +00:00
print('alice@' + aliceDomain + ':' + str(alicePort) + ' in ' +
bobFollowersFilename)
assert 'alice@' + aliceDomain + ':' + str(alicePort) in \
open(bobFollowersFilename).read()
print('bob@' + bobDomain + ':' + str(bobPort) + ' in ' +
aliceFollowingFilename)
assert 'bob@' + bobDomain + ':' + str(bobPort) in \
open(aliceFollowingFilename).read()
assert validInbox(bobDir, 'bob', bobDomain)
assert validInboxFilenames(bobDir, 'bob', bobDomain,
aliceDomain, alicePort)
2019-07-17 17:16:48 +00:00
2021-08-20 11:22:20 +00:00
print('\n\nEVENT: Bob follows Alice')
2020-04-05 13:25:47 +00:00
sendFollowRequestViaServer(aliceDir, sessionAlice,
'bob', 'bobpass',
bobDomain, bobPort,
'alice', aliceDomain, alicePort,
httpPrefix,
cachedWebfingers, personCache,
True, __version__, signingPrivateKeyPem)
2019-07-17 17:16:48 +00:00
for t in range(10):
2020-04-05 13:25:47 +00:00
if os.path.isfile(aliceDir + '/accounts/alice@' + aliceDomain +
'/followers.txt'):
if 'bob@' + bobDomain + ':' + str(bobPort) in \
open(aliceDir + '/accounts/alice@' + aliceDomain +
'/followers.txt').read():
if os.path.isfile(bobDir + '/accounts/bob@' + bobDomain +
'/following.txt'):
2020-07-03 21:56:38 +00:00
aliceHandleStr = \
'alice@' + aliceDomain + ':' + str(alicePort)
if aliceHandleStr in \
2020-04-05 13:25:47 +00:00
open(bobDir + '/accounts/bob@' + bobDomain +
'/following.txt').read():
2020-07-03 21:56:38 +00:00
if os.path.isfile(bobDir + '/accounts/bob@' +
bobDomain +
'/followingCalendar.txt'):
if aliceHandleStr in \
open(bobDir + '/accounts/bob@' + bobDomain +
'/followingCalendar.txt').read():
break
2019-07-17 17:16:48 +00:00
time.sleep(1)
2020-04-05 13:25:47 +00:00
assert os.path.isfile(aliceDir + '/accounts/alice@' + aliceDomain +
'/followers.txt')
assert os.path.isfile(bobDir + '/accounts/bob@' + bobDomain +
'/following.txt')
assert 'bob@' + bobDomain + ':' + str(bobPort) in \
open(aliceDir + '/accounts/alice@' + aliceDomain +
'/followers.txt').read()
assert 'alice@' + aliceDomain + ':' + str(alicePort) in \
open(bobDir + '/accounts/bob@' + bobDomain + '/following.txt').read()
2020-06-09 11:03:59 +00:00
sessionBob = createSession(proxyType)
2020-04-05 13:25:47 +00:00
password = 'bobpass'
outboxPath = bobDir + '/accounts/bob@' + bobDomain + '/outbox'
inboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/inbox'
2021-08-20 11:22:20 +00:00
print(str(len([name for name in os.listdir(bobOutboxPath)
if os.path.isfile(os.path.join(bobOutboxPath, name))])))
showTestBoxes('alice', aliceInboxPath, aliceOutboxPath)
showTestBoxes('bob', bobInboxPath, bobOutboxPath)
assert len([name for name in os.listdir(bobOutboxPath)
if os.path.isfile(os.path.join(bobOutboxPath, name))]) == 1
print(str(len([name for name in os.listdir(aliceInboxPath)
2021-08-20 11:23:46 +00:00
if os.path.isfile(os.path.join(aliceInboxPath, name))])))
2021-08-20 11:22:20 +00:00
showTestBoxes('alice', aliceInboxPath, aliceOutboxPath)
showTestBoxes('bob', bobInboxPath, bobOutboxPath)
assert len([name for name in os.listdir(aliceInboxPath)
if os.path.isfile(os.path.join(aliceInboxPath, name))]) == 0
print('\n\nEVENT: Bob likes the post')
2020-04-05 13:25:47 +00:00
sendLikeViaServer(bobDir, sessionBob,
'bob', 'bobpass',
bobDomain, bobPort,
httpPrefix, outboxPostId,
cachedWebfingers, personCache,
True, __version__, signingPrivateKeyPem)
for i in range(20):
2020-03-22 21:16:02 +00:00
if os.path.isdir(outboxPath) and os.path.isdir(inboxPath):
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 2:
test = len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
if test == 1:
break
time.sleep(1)
2021-08-20 11:22:20 +00:00
showTestBoxes('alice', aliceInboxPath, aliceOutboxPath)
showTestBoxes('bob', bobInboxPath, bobOutboxPath)
assert len([name for name in os.listdir(bobOutboxPath)
if os.path.isfile(os.path.join(bobOutboxPath, name))]) == 2
assert len([name for name in os.listdir(aliceInboxPath)
if os.path.isfile(os.path.join(aliceInboxPath, name))]) == 0
print('EVENT: Post liked')
2020-03-22 21:16:02 +00:00
2020-04-05 13:25:47 +00:00
print(str(len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))])))
2021-08-20 11:22:20 +00:00
showTestBoxes('alice', aliceInboxPath, aliceOutboxPath)
showTestBoxes('bob', bobInboxPath, bobOutboxPath)
2020-04-05 13:25:47 +00:00
assert len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 2
print(str(len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])))
2021-08-20 11:22:20 +00:00
assert len([name for name in os.listdir(aliceInboxPath)
if os.path.isfile(os.path.join(aliceInboxPath, name))]) == 0
showTestBoxes('alice', aliceInboxPath, aliceOutboxPath)
showTestBoxes('bob', bobInboxPath, bobOutboxPath)
print('\n\nEVENT: Bob repeats the post')
signingPrivateKeyPem = None
2020-04-05 13:25:47 +00:00
sendAnnounceViaServer(bobDir, sessionBob, 'bob', password,
bobDomain, bobPort,
httpPrefix, outboxPostId,
cachedWebfingers,
personCache, True, __version__,
signingPrivateKeyPem)
2019-07-16 22:57:45 +00:00
for i in range(20):
2020-03-22 21:16:02 +00:00
if os.path.isdir(outboxPath) and os.path.isdir(inboxPath):
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 3:
if len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath,
name))]) == 2:
2019-07-16 22:57:45 +00:00
break
2019-07-16 19:07:45 +00:00
time.sleep(1)
2021-08-20 11:22:20 +00:00
showTestBoxes('alice', aliceInboxPath, aliceOutboxPath)
showTestBoxes('bob', bobInboxPath, bobOutboxPath)
assert len([name for name in os.listdir(bobOutboxPath)
if os.path.isfile(os.path.join(bobOutboxPath, name))]) == 4
2021-08-20 11:22:20 +00:00
assert len([name for name in os.listdir(aliceInboxPath)
if os.path.isfile(os.path.join(aliceInboxPath, name))]) == 1
print('EVENT: Post repeated')
2019-07-17 11:54:13 +00:00
2020-04-05 13:25:47 +00:00
inboxPath = bobDir + '/accounts/bob@' + bobDomain + '/inbox'
outboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox'
postsBefore = \
len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
2021-08-20 11:22:20 +00:00
print('\n\nEVENT: Alice deletes her post: ' + outboxPostId + ' ' +
2020-04-05 13:25:47 +00:00
str(postsBefore))
password = 'alicepass'
sendDeleteViaServer(aliceDir, sessionAlice, 'alice', password,
aliceDomain, alicePort,
httpPrefix, outboxPostId,
cachedWebfingers, personCache,
True, __version__, signingPrivateKeyPem)
2019-07-17 17:16:48 +00:00
for i in range(30):
if os.path.isdir(inboxPath):
2020-04-05 13:25:47 +00:00
test = len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
if test == postsBefore-1:
2019-07-17 17:16:48 +00:00
break
time.sleep(1)
2020-04-05 13:25:47 +00:00
test = len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
assert test == postsBefore - 1
2019-07-17 17:16:48 +00:00
print(">>> post deleted from Alice's outbox and Bob's inbox")
2020-04-05 13:25:47 +00:00
assert validInbox(bobDir, 'bob', bobDomain)
assert validInboxFilenames(bobDir, 'bob', bobDomain,
aliceDomain, alicePort)
2020-03-22 21:16:02 +00:00
2021-08-20 11:22:20 +00:00
print('\n\nEVENT: Alice unfollows Bob')
2020-04-05 13:25:47 +00:00
password = 'alicepass'
sendUnfollowRequestViaServer(baseDir, sessionAlice,
'alice', password,
aliceDomain, alicePort,
'bob', bobDomain, bobPort,
httpPrefix,
cachedWebfingers, personCache,
True, __version__, signingPrivateKeyPem)
2019-07-17 11:54:13 +00:00
for t in range(10):
2020-04-05 13:25:47 +00:00
if 'alice@' + aliceDomain + ':' + str(alicePort) not in \
open(bobFollowersFilename).read():
if 'bob@' + bobDomain + ':' + str(bobPort) not in \
open(aliceFollowingFilename).read():
2019-07-17 11:54:13 +00:00
break
time.sleep(1)
2020-03-02 21:28:22 +00:00
assert os.path.isfile(bobFollowersFilename)
assert os.path.isfile(aliceFollowingFilename)
2020-04-05 13:25:47 +00:00
assert 'alice@' + aliceDomain + ':' + str(alicePort) \
not in open(bobFollowersFilename).read()
assert 'bob@' + bobDomain + ':' + str(bobPort) \
not in open(aliceFollowingFilename).read()
assert validInbox(bobDir, 'bob', bobDomain)
assert validInboxFilenames(bobDir, 'bob', bobDomain,
aliceDomain, alicePort)
assert validInbox(aliceDir, 'alice', aliceDomain)
assert validInboxFilenames(aliceDir, 'alice', aliceDomain,
bobDomain, bobPort)
2019-07-17 11:54:13 +00:00
2019-07-16 11:33:40 +00:00
# stop the servers
thrAlice.kill()
thrAlice.join()
2020-12-18 15:29:12 +00:00
assert thrAlice.is_alive() is False
2019-07-16 11:33:40 +00:00
thrBob.kill()
thrBob.join()
2020-12-18 15:29:12 +00:00
assert thrBob.is_alive() is False
2019-07-16 11:33:40 +00:00
os.chdir(baseDir)
2020-04-05 13:25:47 +00:00
# shutil.rmtree(aliceDir)
# shutil.rmtree(bobDir)
2019-07-16 10:19:04 +00:00
def _testActorParsing():
2019-08-21 16:35:46 +00:00
print('testActorParsing')
2020-04-05 13:25:47 +00:00
actor = 'https://mydomain:72/users/mynick'
domain, port = getDomainFromActor(actor)
assert domain == 'mydomain'
assert port == 72
nickname = getNicknameFromActor(actor)
assert nickname == 'mynick'
2020-08-13 16:41:02 +00:00
actor = 'https://element/accounts/badger'
domain, port = getDomainFromActor(actor)
assert domain == 'element'
nickname = getNicknameFromActor(actor)
assert nickname == 'badger'
actor = 'egg@chicken.com'
domain, port = getDomainFromActor(actor)
assert domain == 'chicken.com'
nickname = getNicknameFromActor(actor)
assert nickname == 'egg'
actor = '@waffle@cardboard'
domain, port = getDomainFromActor(actor)
assert domain == 'cardboard'
nickname = getNicknameFromActor(actor)
assert nickname == 'waffle'
actor = 'https://astral/channel/sky'
domain, port = getDomainFromActor(actor)
assert domain == 'astral'
nickname = getNicknameFromActor(actor)
assert nickname == 'sky'
2020-04-05 13:25:47 +00:00
actor = 'https://randomain/users/rando'
domain, port = getDomainFromActor(actor)
assert domain == 'randomain'
nickname = getNicknameFromActor(actor)
assert nickname == 'rando'
actor = 'https://otherdomain:49/@othernick'
domain, port = getDomainFromActor(actor)
assert domain == 'otherdomain'
assert port == 49
nickname = getNicknameFromActor(actor)
assert nickname == 'othernick'
2019-08-21 16:35:46 +00:00
def _testWebLinks():
2019-09-01 08:57:51 +00:00
print('testWebLinks')
2020-01-24 10:52:59 +00:00
2021-03-17 21:17:27 +00:00
exampleText = \
"<p>Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + \
" <a href=\"https://domain.ugh/tags/turbot\" class=\"mention " + \
"hashtag\" rel=\"tag\">#<span>turbot</span></a> <a href=\"" + \
"https://domain.ugh/tags/haddock\" class=\"mention hashtag\"" + \
" rel=\"tag\">#<span>haddock</span></a></p>"
resultText = removeLongWords(exampleText, 40, [])
assert resultText == "<p>Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + \
" <a href=\"https://domain.ugh/tags/turbot\" class=\"mention " + \
"hashtag\" rel=\"tag\">#<span>turbot</span></a> " + \
"<a href=\"https://domain.ugh/tags/haddock\" " + \
"class=\"mention hashtag\" rel=\"tag\">#<span>haddock</span></a></p>"
2020-04-05 13:25:47 +00:00
exampleText = \
'<p><span class=\"h-card\"><a href=\"https://something/@orother' + \
'\" class=\"u-url mention\">@<span>foo</span></a></span> Some ' + \
'random text.</p><p>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + \
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + \
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + \
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + \
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + \
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</p>'
resultText = removeLongWords(exampleText, 40, [])
assert resultText == \
'<p><span class="h-card"><a href="https://something/@orother"' + \
' class="u-url mention">@<span>foo</span></a></span> ' + \
'Some random text.</p>'
exampleText = \
'This post has a web links https://somesite.net\n\nAnd some other text'
linkedText = addWebLinks(exampleText)
assert \
2020-12-13 11:31:16 +00:00
'<a href="https://somesite.net" rel="nofollow noopener noreferrer"' + \
2020-04-05 13:25:47 +00:00
' target="_blank"><span class="invisible">https://' + \
'</span><span class="ellipsis">somesite.net</span></a' in linkedText
exampleText = \
'This post has a very long web link\n\nhttp://' + \
'cbwebewuvfuftdiudbqd33dddbbyuef23fyug3bfhcyu2fct2' + \
'cuyqbcbucuwvckiwyfgewfvqejbchevbhwevuevwbqebqekve' + \
'qvuvjfkf.onion\n\nAnd some other text'
linkedText = addWebLinks(exampleText)
2019-10-01 10:36:51 +00:00
assert 'ellipsis' in linkedText
2020-01-24 10:52:59 +00:00
2020-04-05 13:25:47 +00:00
exampleText = \
'<p>1. HAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAH' + \
'AHAHAHHAHAHAHAHAHAHAHAHAHAHAHAHHAHAHAHAHAHAHAHAH</p>'
resultText = removeLongWords(exampleText, 40, [])
assert resultText == '<p>1. HAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHA</p>'
exampleText = \
'<p>Tox address is 88AB9DED6F9FBEF43E105FB72060A2D89F9B93C74' + \
'4E8C45AB3C5E42C361C837155AFCFD9D448 </p>'
resultText = removeLongWords(exampleText, 40, [])
assert resultText == exampleText
2020-10-31 23:10:38 +00:00
exampleText = \
'some.incredibly.long.and.annoying.word.which.should.be.removed: ' + \
'The remaining text'
resultText = removeLongWords(exampleText, 40, [])
assert resultText == \
'some.incredibly.long.and.annoying.word.w\n' + \
'hich.should.be.removed: The remaining text'
2020-04-05 13:25:47 +00:00
exampleText = \
'<p>Tox address is 88AB9DED6F9FBEF43E105FB72060A2D89F9B93C74' + \
'4E8C45AB3C5E42C361C837155AFCFD9D448</p>'
resultText = removeLongWords(exampleText, 40, [])
assert resultText == \
'<p>Tox address is 88AB9DED6F9FBEF43E105FB72060A2D89F9B93C7\n' + \
'44E8C45AB3C5E42C361C837155AFCFD9D448</p>'
exampleText = \
'<p>ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCA' + \
'BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB' + \
'CABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC' + \
'ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCA' + \
'BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB' + \
'CABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC' + \
'ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCA' + \
'BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB' + \
'CABCABCABCABCABCABCABCABC</p>'
resultText = removeLongWords(exampleText, 40, [])
assert resultText == r'<p>ABCABCABCABCABCABCABCABCABCABCABCABCABCA<\p>'
exampleText = \
'"the nucleus of mutual-support institutions, habits, and customs ' + \
'remains alive with the millions; it keeps them together; and ' + \
'they prefer to cling to their customs, beliefs, and traditions ' + \
'rather than to accept the teachings of a war of each ' + \
'against all"\n\n--Peter Kropotkin'
testFnStr = addWebLinks(exampleText)
resultText = removeLongWords(testFnStr, 40, [])
2020-04-05 13:25:47 +00:00
assert resultText == exampleText
2020-03-29 10:48:31 +00:00
assert 'ellipsis' not in resultText
2020-03-29 09:59:54 +00:00
2020-05-12 09:34:58 +00:00
exampleText = \
'<p>' + \
'<<\\p>'
2020-05-12 09:34:58 +00:00
resultText = replaceContentDuplicates(exampleText)
assert resultText == \
'<p>' + \
''
2020-08-07 20:51:34 +00:00
exampleText = \
2020-08-11 17:18:22 +00:00
'<p>Test1 test2 #YetAnotherExcessivelyLongwindedAndBoringHashtag</p>'
testFnStr = addWebLinks(exampleText)
resultText = removeLongWords(testFnStr, 40, [])
2020-08-07 20:51:34 +00:00
assert(resultText ==
'<p>Test1 test2 '
'#YetAnotherExcessivelyLongwindedAndBorin\ngHashtag</p>')
2020-12-06 10:18:41 +00:00
exampleText = \
2020-12-06 14:47:06 +00:00
"<p>Don't remove a p2p link " + \
"rad:git:hwd1yrerc3mcgn8ga9rho3dqi4w33nep7kxmqezss4topyfgmexihp" + \
"33xcw</p>"
testFnStr = addWebLinks(exampleText)
resultText = removeLongWords(testFnStr, 40, [])
2020-12-06 10:18:41 +00:00
assert resultText == exampleText
2020-01-24 10:52:59 +00:00
def _testAddEmoji():
2020-02-21 15:09:31 +00:00
print('testAddEmoji')
2020-04-05 13:25:47 +00:00
content = "Emoji :lemon: :strawberry: :banana:"
httpPrefix = 'http'
nickname = 'testuser'
domain = 'testdomain.net'
port = 3682
recipients = []
hashtags = {}
baseDir = os.getcwd()
baseDirOriginal = os.getcwd()
path = baseDir + '/.tests'
2019-09-29 18:48:34 +00:00
if not os.path.isdir(path):
os.mkdir(path)
2020-04-05 13:25:47 +00:00
path = baseDir + '/.tests/emoji'
2019-09-29 18:48:34 +00:00
if os.path.isdir(path):
shutil.rmtree(path)
2020-03-22 21:16:02 +00:00
os.mkdir(path)
2020-04-05 13:25:47 +00:00
baseDir = path
path = baseDir + '/emoji'
2019-09-29 18:48:34 +00:00
if os.path.isdir(path):
shutil.rmtree(path)
2020-03-22 21:16:02 +00:00
os.mkdir(path)
2020-04-05 13:25:47 +00:00
copytree(baseDirOriginal + '/emoji', baseDir + '/emoji')
2019-09-29 18:48:34 +00:00
os.chdir(baseDir)
2020-04-05 13:25:47 +00:00
privateKeyPem, publicKeyPem, person, wfEndpoint = \
createPerson(baseDir, nickname, domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, 'password')
2020-04-05 13:25:47 +00:00
contentModified = \
addHtmlTags(baseDir, httpPrefix,
nickname, domain, content,
recipients, hashtags, True)
2020-02-21 15:09:31 +00:00
assert ':lemon:' in contentModified
2020-02-21 09:53:36 +00:00
assert contentModified.startswith('<p>')
assert contentModified.endswith('</p>')
2020-04-05 13:25:47 +00:00
tags = []
for tagName, tag in hashtags.items():
2019-09-29 18:48:34 +00:00
tags.append(tag)
2020-04-05 13:25:47 +00:00
content = contentModified
contentModified = replaceEmojiFromTags(content, tags, 'content')
2021-06-22 12:42:52 +00:00
# print('contentModified: ' + contentModified)
2020-04-05 13:25:47 +00:00
assert contentModified == '<p>Emoji 🍋 🍓 🍌</p>'
2019-09-29 18:48:34 +00:00
os.chdir(baseDirOriginal)
2020-04-05 13:25:47 +00:00
shutil.rmtree(baseDirOriginal + '/.tests')
2019-09-29 18:48:34 +00:00
def _testGetStatusNumber():
2019-10-12 12:45:53 +00:00
print('testGetStatusNumber')
2020-04-05 13:25:47 +00:00
prevStatusNumber = None
for i in range(1, 20):
statusNumber, published = getStatusNumber()
2019-10-12 12:45:53 +00:00
if prevStatusNumber:
assert len(statusNumber) == 18
assert int(statusNumber) > prevStatusNumber
2020-04-05 13:25:47 +00:00
prevStatusNumber = int(statusNumber)
2019-10-12 12:45:53 +00:00
def _testJsonString() -> None:
2020-10-11 12:41:15 +00:00
print('testJsonString')
2020-10-11 13:00:26 +00:00
filename = '.epicyon_tests_testJsonString.json'
2020-04-05 13:25:47 +00:00
messageStr = "Crème brûlée यह एक परीक्षण ह"
testJson = {
2019-11-09 12:13:39 +00:00
"content": messageStr
}
2020-04-05 13:25:47 +00:00
assert saveJson(testJson, filename)
receivedJson = loadJson(filename, 0)
2019-11-09 12:13:39 +00:00
assert receivedJson
2020-04-05 13:25:47 +00:00
assert receivedJson['content'] == messageStr
encodedStr = json.dumps(testJson, ensure_ascii=False)
assert messageStr in encodedStr
try:
os.remove(filename)
except BaseException:
pass
2019-11-09 12:13:39 +00:00
2020-04-05 13:25:47 +00:00
def _testSaveLoadJson():
2019-11-23 10:13:57 +00:00
print('testSaveLoadJson')
2020-04-05 13:25:47 +00:00
testJson = {
2019-11-23 10:13:57 +00:00
"param1": 3,
2019-11-23 10:20:30 +00:00
"param2": '"Crème brûlée यह एक परीक्षण ह"'
2019-11-23 10:13:57 +00:00
}
2020-10-11 13:03:08 +00:00
testFilename = '.epicyon_tests_testSaveLoadJson.json'
2019-11-23 10:13:57 +00:00
if os.path.isfile(testFilename):
try:
os.remove(testFilename)
except BaseException:
pass
2020-04-05 13:25:47 +00:00
assert saveJson(testJson, testFilename)
2019-11-23 10:13:57 +00:00
assert os.path.isfile(testFilename)
2020-04-05 13:25:47 +00:00
testLoadJson = loadJson(testFilename)
2019-11-23 10:13:57 +00:00
assert(testLoadJson)
assert testLoadJson.get('param1')
assert testLoadJson.get('param2')
2020-04-05 13:25:47 +00:00
assert testLoadJson['param1'] == 3
assert testLoadJson['param2'] == '"Crème brûlée यह एक परीक्षण ह"'
try:
os.remove(testFilename)
except BaseException:
pass
2019-11-23 13:04:11 +00:00
2020-04-05 13:25:47 +00:00
def _testTheme():
2019-11-23 13:04:11 +00:00
print('testTheme')
2020-04-05 13:25:47 +00:00
css = 'somestring --background-value: 24px; --foreground-value: 24px;'
result = setCSSparam(css, 'background-value', '32px')
assert result == \
'somestring --background-value: 32px; --foreground-value: 24px;'
css = \
'somestring --background-value: 24px; --foreground-value: 24px; ' + \
'--background-value: 24px;'
result = setCSSparam(css, 'background-value', '32px')
assert result == \
'somestring --background-value: 32px; --foreground-value: 24px; ' + \
'--background-value: 32px;'
css = '--background-value: 24px; --foreground-value: 24px;'
result = setCSSparam(css, 'background-value', '32px')
assert result == '--background-value: 32px; --foreground-value: 24px;'
2019-11-23 13:04:11 +00:00
def _testRecentPostsCache():
print('testRecentPostsCache')
2020-04-05 13:25:47 +00:00
recentPostsCache = {}
maxRecentPosts = 3
htmlStr = '<html></html>'
for i in range(5):
2020-04-05 13:25:47 +00:00
postJsonObject = {
2021-06-22 12:42:52 +00:00
"id": "https://somesite.whatever/users/someuser/statuses/" + str(i)
}
2020-04-05 13:25:47 +00:00
updateRecentPostsCache(recentPostsCache, maxRecentPosts,
postJsonObject, htmlStr)
assert len(recentPostsCache['index']) == maxRecentPosts
assert len(recentPostsCache['json'].items()) == maxRecentPosts
assert len(recentPostsCache['html'].items()) == maxRecentPosts
def _testRemoveTextFormatting():
print('testRemoveTextFormatting')
testStr = '<p>Text without formatting</p>'
resultStr = removeTextFormatting(testStr)
assert(resultStr == testStr)
testStr = '<p>Text <i>with</i> <h3>formatting</h3></p>'
resultStr = removeTextFormatting(testStr)
assert(resultStr == '<p>Text with formatting</p>')
def _testJsonld():
2020-06-15 12:37:53 +00:00
print("testJsonld")
2020-06-15 12:37:53 +00:00
jldDocument = {
"@context": "https://www.w3.org/ns/activitystreams",
"actor": "https://somesite.net/users/gerbil",
2020-06-15 12:37:53 +00:00
"description": "My json document",
"numberField": 83582,
"object": {
2021-01-03 14:34:27 +00:00
"content": "valid content"
2020-06-15 12:37:53 +00:00
}
}
# privateKeyPem, publicKeyPem = generateRSAKey()
privateKeyPem = '-----BEGIN RSA PRIVATE KEY-----\n' \
'MIIEowIBAAKCAQEAod9iHfIn4ugY/2byFrFjUprrFLkkH5bCrjiBq2/MdHFg99IQ\n' \
'7li2x2mg5fkBMhU5SJIxlN8kiZMFq7JUXSA97Yo4puhVubqTSHihIh6Xn2mTjTgs\n' \
'zNo9SBbmN3YiyBPTcr0rF4jGWZAduJ8u6i7Eky2QH+UBKyUNRZrcfoVq+7grHUIA\n' \
'45pE7vAfEEWtgRiw32Nwlx55N3hayHax0y8gMdKEF/vfYKRLcM7rZgEASMtlCpgy\n' \
'fsyHwFCDzl/BP8AhP9u3dM+SEundeAvF58AiXx1pKvBpxqttDNAsKWCRQ06/WI/W\n' \
'2Rwihl9yCjobqRoFsZ/cTEi6FG9AbDAds5YjTwIDAQABAoIBAERL3rbpy8Bl0t43\n' \
'jh7a+yAIMvVMZBxb3InrV3KAug/LInGNFQ2rKnsaawN8uu9pmwCuhfLc7yqIeJUH\n' \
'qaadCuPlNJ/fWQQC309tbfbaV3iv78xejjBkSATZfIqb8nLeQpGflMXaNG3na1LQ\n' \
'/tdZoiDC0ZNTaNnOSTo765oKKqhHUTQkwkGChrwG3Js5jekV4zpPMLhUafXk6ksd\n' \
'8XLlZdCF3RUnuguXAg2xP/duxMYmTCx3eeGPkXBPQl0pahu8/6OtBoYvBrqNdQcx\n' \
'jnEtYX9PCqDY3hAXW9GWsxNfu02DKhWigFHFNRUQtMI++438+QIfzXPslE2bTQIt\n' \
'0OXUlwECgYEAxTKUZ7lwIBb5XKPJq53RQmX66M3ArxI1RzFSKm1+/CmxvYiN0c+5\n' \
'2Aq62WEIauX6hoZ7yQb4zhdeNRzinLR7rsmBvIcP12FidXG37q9v3Vu70KmHniJE\n' \
'TPbt5lHQ0bNACFxkar4Ab/JZN4CkMRgJdlcZ5boYNmcGOYCvw9izuM8CgYEA0iQ1\n' \
'khIFZ6fCiXwVRGvEHmqSnkBmBHz8MY8fczv2Z4Gzfq3Tlh9VxpigK2F2pFt7keWc\n' \
'53HerYFHFpf5otDhEyRwA1LyIcwbj5HopumxsB2WG+/M2as45lLfWa6KO73OtPpU\n' \
'wGZYW+i/otdk9eFphceYtw19mxI+3lYoeI8EjYECgYBxOtTKJkmCs45lqkp/d3QT\n' \
'2zjSempcXGkpQuG6KPtUUaCUgxdj1RISQj792OCbeQh8PDZRvOYaeIKInthkQKIQ\n' \
'P/Z1yVvIQUvmwfBqZmQmR6k1bFLJ80UiqFr7+BiegH2RD3Q9cnIP1aly3DPrWLD+\n' \
'OY9OQKfsfQWu+PxzyTeRMwKBgD8Zjlh5PtQ8RKcB8mTkMzSq7bHFRpzsZtH+1wPE\n' \
'Kp40DRDp41H9wMTsiZPdJUH/EmDh4LaCs8nHuu/m3JfuPtd/pn7pBjntzwzSVFji\n' \
'bW+jwrJK1Gk8B87pbZXBWlLMEOi5Dn/je37Fqd2c7f0DHauFHq9AxsmsteIPXwGs\n' \
'eEKBAoGBAIzJX/5yFp3ObkPracIfOJ/U/HF1UdP6Y8qmOJBZOg5s9Y+JAdY76raK\n' \
'0SbZPsOpuFUdTiRkSI3w/p1IuM5dPxgCGH9MHqjqogU5QwXr3vLF+a/PFhINkn1x\n' \
'lozRZjDcF1y6xHfExotPC973UZnKEviq9/FqOsovZpvSQkzAYSZF\n' \
'-----END RSA PRIVATE KEY-----'
publicKeyPem = '-----BEGIN PUBLIC KEY-----\n' \
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAod9iHfIn4ugY/2byFrFj\n' \
'UprrFLkkH5bCrjiBq2/MdHFg99IQ7li2x2mg5fkBMhU5SJIxlN8kiZMFq7JUXSA9\n' \
'7Yo4puhVubqTSHihIh6Xn2mTjTgszNo9SBbmN3YiyBPTcr0rF4jGWZAduJ8u6i7E\n' \
'ky2QH+UBKyUNRZrcfoVq+7grHUIA45pE7vAfEEWtgRiw32Nwlx55N3hayHax0y8g\n' \
'MdKEF/vfYKRLcM7rZgEASMtlCpgyfsyHwFCDzl/BP8AhP9u3dM+SEundeAvF58Ai\n' \
'Xx1pKvBpxqttDNAsKWCRQ06/WI/W2Rwihl9yCjobqRoFsZ/cTEi6FG9AbDAds5Yj\n' \
'TwIDAQAB\n' \
'-----END PUBLIC KEY-----'
signedDocument = jldDocument.copy()
generateJsonSignature(signedDocument, privateKeyPem)
2020-06-15 12:37:53 +00:00
assert(signedDocument)
2020-06-15 13:35:33 +00:00
assert(signedDocument.get('signature'))
assert(signedDocument['signature'].get('signatureValue'))
assert(signedDocument['signature'].get('type'))
assert(len(signedDocument['signature']['signatureValue']) > 50)
# print(str(signedDocument['signature']))
assert(signedDocument['signature']['type'] == 'RsaSignature2017')
assert(verifyJsonSignature(signedDocument, publicKeyPem))
# alter the signed document
signedDocument['object']['content'] = 'forged content'
assert(not verifyJsonSignature(signedDocument, publicKeyPem))
2020-06-15 12:37:53 +00:00
2021-01-03 15:27:59 +00:00
jldDocument2 = {
"@context": "https://www.w3.org/ns/activitystreams",
"actor": "https://somesite.net/users/gerbil",
2021-01-03 15:27:59 +00:00
"description": "Another json document",
"numberField": 13353,
"object": {
"content": "More content"
}
}
signedDocument2 = jldDocument2.copy()
generateJsonSignature(signedDocument2, privateKeyPem)
2021-01-03 15:27:59 +00:00
assert(signedDocument2)
assert(signedDocument2.get('signature'))
assert(signedDocument2['signature'].get('signatureValue'))
# changed signature on different document
if signedDocument['signature']['signatureValue'] == \
signedDocument2['signature']['signatureValue']:
print('json signature has not changed for different documents')
assert '.' not in str(signedDocument['signature']['signatureValue'])
assert len(str(signedDocument['signature']['signatureValue'])) > 340
assert(signedDocument['signature']['signatureValue'] !=
signedDocument2['signature']['signatureValue'])
2021-01-03 15:27:59 +00:00
2020-06-15 12:37:53 +00:00
def _testSiteIsActive():
2020-06-22 16:55:19 +00:00
print('testSiteIsActive')
assert(siteIsActive('https://archive.org'))
2020-06-22 16:55:19 +00:00
assert(siteIsActive('https://mastodon.social'))
assert(not siteIsActive('https://notarealwebsite.a.b.c'))
def _testRemoveHtml():
print('testRemoveHtml')
testStr = 'This string has no html.'
assert(removeHtml(testStr) == testStr)
testStr = 'This string <a href="1234.567">has html</a>.'
assert(removeHtml(testStr) == 'This string has html.')
2021-03-23 10:52:10 +00:00
testStr = '<label>This string has.</label><label>Two labels.</label>'
assert(removeHtml(testStr) == 'This string has. Two labels.')
2021-03-23 10:38:03 +00:00
testStr = '<p>This string has.</p><p>Two paragraphs.</p>'
2021-03-23 10:52:10 +00:00
assert(removeHtml(testStr) == 'This string has.\n\nTwo paragraphs.')
testStr = 'This string has.<br>A new line.'
assert(removeHtml(testStr) == 'This string has.\nA new line.')
testStr = '<p>This string contains a url http://somesite.or.other</p>'
2021-03-23 11:22:09 +00:00
assert(removeHtml(testStr) ==
2021-03-23 10:52:10 +00:00
'This string contains a url http://somesite.or.other')
def _testDangerousCSS():
2020-12-13 14:48:45 +00:00
print('testDangerousCSS')
baseDir = os.getcwd()
for subdir, dirs, files in os.walk(baseDir):
for f in files:
if not f.endswith('.css'):
continue
assert not dangerousCSS(baseDir + '/' + f, False)
break
def _testDangerousMarkup():
2020-07-10 14:15:01 +00:00
print('testDangerousMarkup')
allowLocalNetworkAccess = False
2020-07-10 14:15:01 +00:00
content = '<p>This is a valid message</p>'
assert(not dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = 'This is a valid message without markup'
assert(not dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This is a valid-looking message. But wait... ' + \
'<script>document.getElementById("concentrated")' + \
'.innerHTML = "evil";</script></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2021-05-19 11:29:37 +00:00
content = '<p>This is a valid-looking message. But wait... ' + \
'&lt;script&gt;document.getElementById("concentrated")' + \
'.innerHTML = "evil";&lt;/script&gt;</p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-15 10:36:24 +00:00
content = '<p>This html contains more than you expected... ' + \
'<script language="javascript">document.getElementById("abc")' + \
'.innerHTML = "def";</script></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-15 10:36:24 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This is a valid-looking message. But wait... ' + \
'<script src="https://evilsite/payload.js" /></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This message embeds an evil frame.' + \
'<iframe src="somesite"></iframe></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This message tries to obfuscate an evil frame.' + \
'< iframe src = "somesite"></ iframe ></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This message is not necessarily evil, but annoying.' + \
'<hr><br><br><br><br><br><br><br><hr><hr></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This message contans a ' + \
'<a href="https://validsite/index.html">valid link.</a></p>'
assert(not dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This message contans a ' + \
'<a href="https://validsite/iframe.html">' + \
'valid link having invalid but harmless name.</a></p>'
assert(not dangerousMarkup(content, allowLocalNetworkAccess))
2020-07-10 14:15:01 +00:00
2020-11-11 09:42:48 +00:00
content = '<p>This message which <a href="127.0.0.1:8736">' + \
'tries to access the local network</a></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
content = '<p>This message which <a href="http://192.168.5.10:7235">' + \
'tries to access the local network</a></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
content = '<p>127.0.0.1 This message which does not access ' + \
'the local network</a></p>'
assert(not dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
def _runHtmlReplaceQuoteMarks():
2020-08-02 17:01:12 +00:00
print('htmlReplaceQuoteMarks')
testStr = 'The "cat" "sat" on the mat'
result = htmlReplaceQuoteMarks(testStr)
2020-08-02 18:09:50 +00:00
assert result == 'The “cat” “sat” on the mat'
2020-08-02 17:01:12 +00:00
testStr = 'The cat sat on the mat'
result = htmlReplaceQuoteMarks(testStr)
assert result == 'The cat sat on the mat'
testStr = '"hello"'
result = htmlReplaceQuoteMarks(testStr)
2020-08-02 18:09:50 +00:00
assert result == '“hello”'
2020-08-02 17:01:12 +00:00
2020-08-02 19:16:22 +00:00
testStr = '"hello" <a href="somesite.html">&quot;test&quot; html</a>'
2020-08-02 17:17:51 +00:00
result = htmlReplaceQuoteMarks(testStr)
2020-08-02 19:16:22 +00:00
assert result == '“hello” <a href="somesite.html">“test” html</a>'
2020-08-02 17:17:51 +00:00
2020-08-02 17:01:12 +00:00
def _testJsonPostAllowsComments():
2020-08-21 18:32:16 +00:00
print('testJsonPostAllowsComments')
postJsonObject = {
"id": "123"
}
assert jsonPostAllowsComments(postJsonObject)
postJsonObject = {
"id": "123",
"commentsEnabled": False
}
assert not jsonPostAllowsComments(postJsonObject)
postJsonObject = {
"id": "123",
"rejectReplies": False
}
assert jsonPostAllowsComments(postJsonObject)
postJsonObject = {
"id": "123",
"rejectReplies": True
}
assert not jsonPostAllowsComments(postJsonObject)
2020-08-21 18:32:16 +00:00
postJsonObject = {
"id": "123",
"commentsEnabled": True
}
assert jsonPostAllowsComments(postJsonObject)
postJsonObject = {
"id": "123",
"object": {
"commentsEnabled": True
}
}
assert jsonPostAllowsComments(postJsonObject)
postJsonObject = {
"id": "123",
"object": {
"commentsEnabled": False
}
}
assert not jsonPostAllowsComments(postJsonObject)
def _testRemoveIdEnding():
2020-08-23 11:13:35 +00:00
print('testRemoveIdEnding')
testStr = 'https://activitypub.somedomain.net'
resultStr = removeIdEnding(testStr)
assert resultStr == 'https://activitypub.somedomain.net'
testStr = \
'https://activitypub.somedomain.net/users/foo/' + \
'statuses/34544814814/activity'
resultStr = removeIdEnding(testStr)
assert resultStr == \
'https://activitypub.somedomain.net/users/foo/statuses/34544814814'
testStr = \
'https://undo.somedomain.net/users/foo/statuses/34544814814/undo'
resultStr = removeIdEnding(testStr)
assert resultStr == \
'https://undo.somedomain.net/users/foo/statuses/34544814814'
testStr = \
'https://event.somedomain.net/users/foo/statuses/34544814814/event'
resultStr = removeIdEnding(testStr)
assert resultStr == \
'https://event.somedomain.net/users/foo/statuses/34544814814'
def _testValidContentWarning():
2020-08-25 19:35:55 +00:00
print('testValidContentWarning')
resultStr = validContentWarning('Valid content warning')
assert resultStr == 'Valid content warning'
resultStr = validContentWarning('Invalid #content warning')
assert resultStr == 'Invalid content warning'
resultStr = \
validContentWarning('Invalid <a href="somesite">content warning</a>')
assert resultStr == 'Invalid content warning'
def _testTranslations():
2020-08-26 18:21:57 +00:00
print('testTranslations')
2021-08-08 11:16:18 +00:00
baseDir = os.getcwd()
languagesStr = getSupportedLanguages(baseDir)
assert languagesStr
2020-08-26 18:21:57 +00:00
# load all translations into a dict
langDict = {}
for lang in languagesStr:
langJson = loadJson('translations/' + lang + '.json')
2020-08-29 11:14:19 +00:00
if not langJson:
print('Missing language file ' +
'translations/' + lang + '.json')
2020-08-26 18:21:57 +00:00
assert langJson
langDict[lang] = langJson
# load english translations
translationsJson = loadJson('translations/en.json')
# test each english string exists in the other language files
for englishStr, translatedStr in translationsJson.items():
for lang in languagesStr:
langJson = langDict[lang]
if not langJson.get(englishStr):
print(englishStr + ' is missing from ' + lang + '.json')
assert langJson.get(englishStr)
def _testConstantTimeStringCheck():
print('testConstantTimeStringCheck')
assert constantTimeStringCheck('testing', 'testing')
assert not constantTimeStringCheck('testing', '1234')
assert not constantTimeStringCheck('testing', '1234567')
itterations = 256
start = time.time()
for timingTest in range(itterations):
constantTimeStringCheck('nnjfbefefbsnjsdnvbcueftqfeuqfbqefnjeniwufgy',
'nnjfbefefbsnjsdnvbcueftqfeuqfbqefnjeniwufgy')
end = time.time()
avTime1 = ((end - start) * 1000000 / itterations)
# change a single character and observe timing difference
start = time.time()
for timingTest in range(itterations):
constantTimeStringCheck('nnjfbefefbsnjsdnvbcueftqfeuqfbqefnjeniwufgy',
'nnjfbefefbsnjsdnvbcueftqfeuqfbqeznjeniwufgy')
end = time.time()
avTime2 = ((end - start) * 1000000 / itterations)
timeDiffMicroseconds = abs(avTime2 - avTime1)
# time difference should be less than 10uS
2020-10-25 10:10:56 +00:00
assert int(timeDiffMicroseconds) < 10
# change multiple characters and observe timing difference
start = time.time()
for timingTest in range(itterations):
constantTimeStringCheck('nnjfbefefbsnjsdnvbcueftqfeuqfbqefnjeniwufgy',
'ano1befffbsn7sd3vbluef6qseuqfpqeznjgni9bfgi')
end = time.time()
avTime2 = ((end - start) * 1000000 / itterations)
timeDiffMicroseconds = abs(avTime2 - avTime1)
# time difference should be less than 10uS
2020-10-25 10:10:56 +00:00
assert int(timeDiffMicroseconds) < 10
def _testReplaceEmailQuote():
print('testReplaceEmailQuote')
2020-09-14 09:41:44 +00:00
testStr = '<p>This content has no quote.</p>'
assert htmlReplaceEmailQuote(testStr) == testStr
2020-09-14 09:41:44 +00:00
testStr = '<p>This content has no quote.</p>' + \
'<p>With multiple</p><p>lines</p>'
assert htmlReplaceEmailQuote(testStr) == testStr
2020-09-14 11:30:56 +00:00
testStr = '<p>&quot;This is a quoted paragraph.&quot;</p>'
assert htmlReplaceEmailQuote(testStr) == \
'<p><blockquote>This is a quoted paragraph.</blockquote></p>'
testStr = "<p><span class=\"h-card\">" + \
"<a href=\"https://somewebsite/@nickname\" " + \
"class=\"u-url mention\">@<span>nickname</span></a></span> " + \
"<br />&gt; This is a quote</p><p>Some other text.</p>"
expectedStr = "<p><span class=\"h-card\">" + \
"<a href=\"https://somewebsite/@nickname\" " + \
"class=\"u-url mention\">@<span>nickname</span></a></span> " + \
"<br /><blockquote>This is a quote</blockquote></p>" + \
"<p>Some other text.</p>"
resultStr = htmlReplaceEmailQuote(testStr)
if resultStr != expectedStr:
2020-09-30 22:52:39 +00:00
print('Result: ' + str(resultStr))
print('Expect: ' + expectedStr)
assert resultStr == expectedStr
2020-09-14 10:25:12 +00:00
testStr = "<p>Some text:</p><p>&gt; first line-&gt;second line</p>" + \
"<p>Some question?</p>"
expectedStr = "<p>Some text:</p><p><blockquote>first line-<br>" + \
"second line</blockquote></p><p>Some question?</p>"
resultStr = htmlReplaceEmailQuote(testStr)
if resultStr != expectedStr:
2020-09-30 22:52:39 +00:00
print('Result: ' + str(resultStr))
2020-09-14 10:25:12 +00:00
print('Expect: ' + expectedStr)
assert resultStr == expectedStr
2020-09-30 22:22:42 +00:00
testStr = "<p><span class=\"h-card\">" + \
"<a href=\"https://somedomain/@somenick\" " + \
"class=\"u-url mention\">@<span>somenick</span>" + \
"</a></span> </p><p>&gt; Text1.<br />&gt; <br />" + \
"&gt; Text2<br />&gt; <br />&gt; Text3<br />" + \
"&gt;<br />&gt; Text4<br />&gt; <br />&gt; " + \
"Text5<br />&gt; <br />&gt; Text6</p><p>Text7</p>"
2020-09-30 22:55:53 +00:00
expectedStr = "<p><span class=\"h-card\">" + \
"<a href=\"https://somedomain/@somenick\" " + \
"class=\"u-url mention\">@<span>somenick</span></a>" + \
"</span> </p><p><blockquote> Text1.<br /><br />" + \
"Text2<br /><br />Text3<br />&gt;<br />Text4<br />" + \
"<br />Text5<br /><br />Text6</blockquote></p><p>Text7</p>"
2020-09-30 22:22:42 +00:00
resultStr = htmlReplaceEmailQuote(testStr)
if resultStr != expectedStr:
2020-09-30 22:52:39 +00:00
print('Result: ' + str(resultStr))
2020-09-30 22:22:42 +00:00
print('Expect: ' + expectedStr)
assert resultStr == expectedStr
def _testRemoveHtmlTag():
2020-10-11 09:33:31 +00:00
print('testRemoveHtmlTag')
testStr = "<p><img width=\"864\" height=\"486\" " + \
"src=\"https://somesiteorother.com/image.jpg\"></p>"
resultStr = removeHtmlTag(testStr, 'width')
assert resultStr == "<p><img height=\"486\" " + \
"src=\"https://somesiteorother.com/image.jpg\"></p>"
def _testHashtagRuleTree():
2020-10-17 12:05:41 +00:00
print('testHashtagRuleTree')
2020-10-20 17:37:15 +00:00
operators = ('not', 'and', 'or', 'xor', 'from', 'contains')
2020-10-17 12:05:41 +00:00
2020-10-20 17:37:15 +00:00
url = 'testsite.com'
2020-10-18 15:10:36 +00:00
moderated = True
conditionsStr = \
'contains "Cat" or contains "Corvid" or ' + \
'contains "Dormouse" or contains "Buzzard"'
tagsInConditions = []
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
assert str(tree) == str(['or', ['contains', ['"Cat"']],
['contains', ['"Corvid"']],
['contains', ['"Dormouse"']],
['contains', ['"Buzzard"']]])
content = 'This is a test'
2020-10-17 17:36:10 +00:00
moderated = True
2020-10-17 12:05:41 +00:00
conditionsStr = '#foo or #bar'
tagsInConditions = []
2020-10-17 17:36:10 +00:00
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
2020-10-17 12:05:41 +00:00
assert str(tree) == str(['or', ['#foo'], ['#bar']])
assert str(tagsInConditions) == str(['#foo', '#bar'])
hashtags = ['#foo']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
hashtags = ['#carrot', '#stick']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
content = 'This is a test'
url = 'https://testsite.com/something'
moderated = True
conditionsStr = '#foo and from "testsite.com"'
tagsInConditions = []
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
assert str(tree) == str(['and', ['#foo'], ['from', ['"testsite.com"']]])
assert str(tagsInConditions) == str(['#foo'])
hashtags = ['#foo']
2020-10-21 10:39:09 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content,
'othersite.net')
content = 'This is a test'
moderated = True
conditionsStr = 'contains "is a" and #foo or #bar'
tagsInConditions = []
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
assert str(tree) == \
str(['and', ['contains', ['"is a"']],
['or', ['#foo'], ['#bar']]])
assert str(tagsInConditions) == str(['#foo', '#bar'])
hashtags = ['#foo']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
hashtags = ['#carrot', '#stick']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 17:36:10 +00:00
moderated = False
conditionsStr = 'not moderated and #foo or #bar'
tagsInConditions = []
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
assert str(tree) == \
str(['not', ['and', ['moderated'], ['or', ['#foo'], ['#bar']]]])
assert str(tagsInConditions) == str(['#foo', '#bar'])
hashtags = ['#foo']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 17:36:10 +00:00
hashtags = ['#carrot', '#stick']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 17:36:10 +00:00
moderated = True
conditionsStr = 'moderated and #foo or #bar'
tagsInConditions = []
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
assert str(tree) == \
str(['and', ['moderated'], ['or', ['#foo'], ['#bar']]])
assert str(tagsInConditions) == str(['#foo', '#bar'])
hashtags = ['#foo']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 17:36:10 +00:00
hashtags = ['#carrot', '#stick']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
conditionsStr = 'x'
tagsInConditions = []
2020-10-17 17:36:10 +00:00
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
2020-10-17 12:05:41 +00:00
assert tree is None
assert tagsInConditions == []
hashtags = ['#foo']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
conditionsStr = '#x'
tagsInConditions = []
2020-10-17 17:36:10 +00:00
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
2020-10-17 12:05:41 +00:00
assert str(tree) == str(['#x'])
assert str(tagsInConditions) == str(['#x'])
hashtags = ['#x']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
hashtags = ['#y', '#z']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
conditionsStr = 'not #b'
tagsInConditions = []
2020-10-17 17:36:10 +00:00
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
2020-10-17 12:05:41 +00:00
assert str(tree) == str(['not', ['#b']])
assert str(tagsInConditions) == str(['#b'])
hashtags = ['#y', '#z']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
hashtags = ['#a', '#b', '#c']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
conditionsStr = '#foo or #bar and #a'
tagsInConditions = []
2020-10-17 17:36:10 +00:00
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
2020-10-17 12:05:41 +00:00
assert str(tree) == str(['and', ['or', ['#foo'], ['#bar']], ['#a']])
assert str(tagsInConditions) == str(['#foo', '#bar', '#a'])
2020-10-18 15:10:36 +00:00
hashtags = ['#foo', '#bar', '#a']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
hashtags = ['#bar', '#a']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
hashtags = ['#foo', '#a']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
hashtags = ['#x', '#a']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
def _testGetNewswireTags():
2020-10-25 10:06:54 +00:00
print('testGetNewswireTags')
2020-10-25 10:24:02 +00:00
rssDescription = '<img src="https://somesite/someimage.jpg" ' + \
2020-10-25 10:08:02 +00:00
'class="misc-stuff" alt="#ExcitingHashtag" ' + \
'srcset="https://somesite/someimage.jpg" ' + \
'sizes="(max-width: 864px) 100vw, 864px" />' + \
'Compelling description with #ExcitingHashtag, which is ' + \
'being posted in #BoringForum'
2020-10-25 10:06:54 +00:00
tags = getNewswireTags(rssDescription, 10)
assert len(tags) == 2
assert '#BoringForum' in tags
assert '#ExcitingHashtag' in tags
def _testFirstParagraphFromString():
2020-11-08 11:24:43 +00:00
print('testFirstParagraphFromString')
testStr = \
'<p><a href="https://somesite.com/somepath">This is a test</a></p>' + \
'<p>This is another paragraph</p>'
resultStr = firstParagraphFromString(testStr)
2021-03-22 14:36:27 +00:00
if resultStr != 'This is a test':
print(resultStr)
2020-11-08 11:24:43 +00:00
assert resultStr == 'This is a test'
testStr = 'Testing without html'
resultStr = firstParagraphFromString(testStr)
assert resultStr == testStr
def _testParseFeedDate():
2020-11-22 18:43:01 +00:00
print('testParseFeedDate')
2020-12-09 10:38:09 +00:00
2020-12-14 15:17:30 +00:00
pubDate = "2020-12-14T00:08:06+00:00"
publishedDate = parseFeedDate(pubDate)
assert publishedDate == "2020-12-14 00:08:06+00:00"
2020-12-09 10:38:09 +00:00
pubDate = "Tue, 08 Dec 2020 06:24:38 -0600"
publishedDate = parseFeedDate(pubDate)
assert publishedDate == "2020-12-08 12:24:38+00:00"
2020-11-22 18:43:01 +00:00
pubDate = "2020-08-27T16:12:34+00:00"
publishedDate = parseFeedDate(pubDate)
2020-11-22 19:13:41 +00:00
assert publishedDate == "2020-08-27 16:12:34+00:00"
2020-11-22 19:01:18 +00:00
pubDate = "Sun, 22 Nov 2020 19:51:33 +0100"
publishedDate = parseFeedDate(pubDate)
2020-11-22 20:18:10 +00:00
assert publishedDate == "2020-11-22 18:51:33+00:00"
2020-11-22 18:43:01 +00:00
def _testValidNickname():
2020-11-24 10:53:10 +00:00
print('testValidNickname')
domain = 'somedomain.net'
nickname = 'myvalidnick'
assert validNickname(domain, nickname)
nickname = 'my.invalid.nick'
assert not validNickname(domain, nickname)
nickname = 'myinvalidnick?'
assert not validNickname(domain, nickname)
nickname = 'my invalid nick?'
assert not validNickname(domain, nickname)
def _testGuessHashtagCategory() -> None:
2020-12-05 11:11:32 +00:00
print('testGuessHashtagCategory')
hashtagCategories = {
"foo": ["swan", "goose"],
2021-07-13 08:43:07 +00:00
"bar": ["cats", "mouse"]
2020-12-05 11:11:32 +00:00
}
guess = guessHashtagCategory("unspecifiedgoose", hashtagCategories)
assert guess == "foo"
2021-07-13 08:43:07 +00:00
guess = guessHashtagCategory("mastocats", hashtagCategories)
2020-12-05 11:11:32 +00:00
assert guess == "bar"
def _testGetMentionedPeople() -> None:
2020-12-13 19:05:26 +00:00
print('testGetMentionedPeople')
baseDir = os.getcwd()
content = "@dragon@cave.site @bat@cave.site This is a test."
actors = getMentionedPeople(baseDir, 'https',
content,
'mydomain', False)
assert actors
assert len(actors) == 2
assert actors[0] == "https://cave.site/users/dragon"
assert actors[1] == "https://cave.site/users/bat"
def _testReplyToPublicPost() -> None:
2020-12-13 19:53:31 +00:00
baseDir = os.getcwd()
2021-07-18 09:55:49 +00:00
systemLanguage = 'en'
2020-12-13 19:53:31 +00:00
nickname = 'test7492362'
domain = 'other.site'
port = 443
httpPrefix = 'https'
postId = httpPrefix + '://rat.site/users/ninjarodent/statuses/63746173435'
2021-05-09 19:11:05 +00:00
content = "@ninjarodent@rat.site This is a test."
followersOnly = False
saveToFile = False
clientToServer = False
commentsEnabled = True
attachImageFilename = None
mediaType = None
imageDescription = 'Some description'
2021-05-09 19:29:53 +00:00
city = 'London, England'
2021-07-01 20:41:17 +00:00
testInReplyToAtomUri = None
testSubject = None
testSchedulePost = False
testEventDate = None
testEventTime = None
testLocation = None
testIsArticle = False
2021-08-08 16:52:32 +00:00
conversationId = None
lowBandwidth = True
2020-12-13 19:53:31 +00:00
reply = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
2021-05-09 19:11:05 +00:00
content, followersOnly, saveToFile,
clientToServer, commentsEnabled,
attachImageFilename, mediaType,
2021-07-01 20:41:17 +00:00
imageDescription, city, postId,
testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId,
lowBandwidth)
2020-12-13 20:07:45 +00:00
# print(str(reply))
2020-12-13 19:53:31 +00:00
assert reply['object']['content'] == \
'<p><span class=\"h-card\">' + \
'<a href=\"https://rat.site/@ninjarodent\" ' + \
'class=\"u-url mention\">@<span>ninjarodent</span>' + \
'</a></span> This is a test.</p>'
reply['object']['contentMap'][systemLanguage] = reply['object']['content']
2020-12-13 19:53:31 +00:00
assert reply['object']['tag'][0]['type'] == 'Mention'
assert reply['object']['tag'][0]['name'] == '@ninjarodent@rat.site'
2021-08-14 08:58:11 +00:00
assert reply['object']['tag'][0]['href'] == 'https://rat.site/@ninjarodent'
2020-12-13 19:53:31 +00:00
assert len(reply['object']['to']) == 1
assert reply['object']['to'][0].endswith('#Public')
assert len(reply['object']['cc']) >= 1
assert reply['object']['cc'][0].endswith(nickname + '/followers')
assert len(reply['object']['tag']) == 1
assert len(reply['object']['cc']) == 2
2021-08-14 08:58:11 +00:00
assert reply['object']['cc'][1] == httpPrefix + '://rat.site/@ninjarodent'
2020-12-13 19:53:31 +00:00
def _getFunctionCallArgs(name: str, lines: [], startLineCtr: int) -> []:
"""Returns the arguments of a function call given lines
of source code and a starting line number
2020-12-22 21:27:46 +00:00
"""
argsStr = lines[startLineCtr].split(name + '(')[1]
if ')' in argsStr:
argsStr = argsStr.split(')')[0].replace(' ', '').split(',')
return argsStr
for lineCtr in range(startLineCtr + 1, len(lines)):
if ')' not in lines[lineCtr]:
argsStr += lines[lineCtr]
continue
else:
argsStr += lines[lineCtr].split(')')[0]
break
return argsStr.replace('\n', '').replace(' ', '').split(',')
2020-12-22 22:55:45 +00:00
def getFunctionCalls(name: str, lines: [], startLineCtr: int,
functionProperties: {}) -> []:
"""Returns the functions called by the given one,
Starting with the given source code at the given line
"""
callsFunctions = []
functionContentStr = ''
for lineCtr in range(startLineCtr + 1, len(lines)):
2020-12-23 12:48:50 +00:00
lineStr = lines[lineCtr].strip()
if lineStr.startswith('def '):
2020-12-22 22:55:45 +00:00
break
2020-12-23 12:48:50 +00:00
if lineStr.startswith('class '):
2020-12-22 22:55:45 +00:00
break
functionContentStr += lines[lineCtr]
for funcName, properties in functionProperties.items():
if funcName + '(' in functionContentStr:
callsFunctions.append(funcName)
return callsFunctions
def _functionArgsMatch(callArgs: [], funcArgs: []):
"""Do the function artuments match the function call arguments
"""
if len(callArgs) == len(funcArgs):
return True
# count non-optional arguments
callArgsCtr = 0
for a in callArgs:
if a == 'self':
continue
2020-12-23 12:48:50 +00:00
if '=' not in a or a.startswith("'"):
callArgsCtr += 1
funcArgsCtr = 0
for a in funcArgs:
if a == 'self':
continue
2020-12-23 12:48:50 +00:00
if '=' not in a or a.startswith("'"):
funcArgsCtr += 1
return callArgsCtr >= funcArgsCtr
2021-06-26 13:46:22 +00:00
def _moduleInGroups(modName: str, includeGroups: [], modGroups: {}) -> bool:
"""Is the given module within the included groups list?
"""
for groupName in includeGroups:
if modName in modGroups[groupName]:
return True
return False
def _diagramGroups(includeGroups: [],
2021-06-26 14:21:24 +00:00
excludeExtraModules: [],
2021-06-26 13:46:22 +00:00
modules: {}, modGroups: {},
maxModuleCalls: int) -> None:
"""Draws a dot diagram containing only the given module groups
"""
callGraphStr = 'digraph EpicyonGroups {\n\n'
callGraphStr += ' graph [fontsize=10 fontname="Verdana" compound=true];\n'
callGraphStr += ' node [fontsize=10 fontname="Verdana"];\n\n'
2021-06-26 14:21:24 +00:00
excludeModulesFromDiagram = [
2021-06-26 15:57:25 +00:00
'setup', 'tests', '__init__', 'pyjsonld'
2021-06-26 14:21:24 +00:00
]
excludeModulesFromDiagram += excludeExtraModules
2021-06-26 13:46:22 +00:00
# colors of modules nodes
for modName, modProperties in modules.items():
if modName in excludeModulesFromDiagram:
continue
if not _moduleInGroups(modName, includeGroups, modGroups):
continue
if not modProperties.get('calls'):
callGraphStr += ' "' + modName + \
'" [fillcolor=yellow style=filled];\n'
continue
if len(modProperties['calls']) <= int(maxModuleCalls / 8):
callGraphStr += ' "' + modName + \
'" [fillcolor=green style=filled];\n'
elif len(modProperties['calls']) < int(maxModuleCalls / 4):
callGraphStr += ' "' + modName + \
'" [fillcolor=orange style=filled];\n'
else:
callGraphStr += ' "' + modName + \
'" [fillcolor=red style=filled];\n'
callGraphStr += '\n'
# connections between modules
for modName, modProperties in modules.items():
if modName in excludeModulesFromDiagram:
continue
if not _moduleInGroups(modName, includeGroups, modGroups):
continue
if not modProperties.get('calls'):
continue
for modCall in modProperties['calls']:
if modCall in excludeModulesFromDiagram:
continue
if not _moduleInGroups(modCall, includeGroups, modGroups):
continue
callGraphStr += ' "' + modName + '" -> "' + modCall + '";\n'
# module groups/clusters
clusterCtr = 1
for groupName, groupModules in modGroups.items():
if groupName not in includeGroups:
continue
callGraphStr += '\n'
callGraphStr += \
' subgraph cluster_' + str(clusterCtr) + ' {\n'
callGraphStr += ' node [style=filled];\n'
for modName in groupModules:
if modName not in excludeModulesFromDiagram:
callGraphStr += ' ' + modName + ';\n'
callGraphStr += ' label = "' + groupName + '";\n'
callGraphStr += ' color = blue;\n'
callGraphStr += ' }\n'
clusterCtr += 1
callGraphStr += '\n}\n'
filename = 'epicyon_groups'
for groupName in includeGroups:
filename += '_' + groupName.replace(' ', '-')
filename += '.dot'
with open(filename, 'w+') as fp:
fp.write(callGraphStr)
print('Graph saved to ' + filename)
print('Plot using: ' +
'sfdp -x -Goverlap=false -Goverlap_scaling=2 ' +
'-Gsep=+100 -Tx11 epicyon_modules.dot')
def _testFunctions():
print('testFunctions')
function = {}
functionProperties = {}
2020-12-22 19:28:34 +00:00
modules = {}
2021-06-15 15:08:12 +00:00
modGroups = {}
2021-06-26 19:01:48 +00:00
methodLOC = []
for subdir, dirs, files in os.walk('.'):
for sourceFile in files:
if not sourceFile.endswith('.py'):
continue
if sourceFile.startswith('.#'):
continue
modName = sourceFile.replace('.py', '')
2020-12-22 19:28:34 +00:00
modules[modName] = {
'functions': []
}
sourceStr = ''
2021-07-13 14:40:49 +00:00
with open(sourceFile, 'r') as f:
sourceStr = f.read()
2020-12-22 19:28:34 +00:00
modules[modName]['source'] = sourceStr
2021-07-13 14:40:49 +00:00
with open(sourceFile, 'r') as f:
lines = f.readlines()
2020-12-22 19:28:34 +00:00
modules[modName]['lines'] = lines
2021-06-26 19:01:48 +00:00
lineCount = 0
prevLine = 'start'
methodName = ''
for line in lines:
2021-06-15 15:08:12 +00:00
if '__module_group__' in line:
if '=' in line:
groupName = line.split('=')[1].strip()
groupName = groupName.replace('"', '')
groupName = groupName.replace("'", '')
modules[modName]['group'] = groupName
if not modGroups.get(groupName):
modGroups[groupName] = [modName]
else:
if modName not in modGroups[groupName]:
modGroups[groupName].append(modName)
2020-12-23 12:48:50 +00:00
if not line.strip().startswith('def '):
2021-06-26 19:01:48 +00:00
if lineCount > 0:
lineCount += 1
2021-06-26 21:29:49 +00:00
# add LOC count for this function
2021-06-26 19:01:48 +00:00
if len(prevLine.strip()) == 0 and \
len(line.strip()) == 0 and \
lineCount > 2:
lineCount -= 2
if lineCount > 80:
locStr = str(lineCount) + ';' + methodName
if lineCount < 1000:
locStr = '0' + locStr
if lineCount < 100:
locStr = '0' + locStr
if lineCount < 10:
locStr = '0' + locStr
if locStr not in methodLOC:
methodLOC.append(locStr)
lineCount = 0
prevLine = line
continue
2021-06-26 19:01:48 +00:00
prevLine = line
lineCount = 1
methodName = line.split('def ', 1)[1].split('(')[0]
methodArgs = \
sourceStr.split('def ' + methodName + '(')[1]
methodArgs = methodArgs.split(')')[0]
methodArgs = methodArgs.replace(' ', '').split(',')
if function.get(modName):
function[modName].append(methodName)
else:
function[modName] = [methodName]
2020-12-22 19:28:34 +00:00
if methodName not in modules[modName]['functions']:
modules[modName]['functions'].append(methodName)
functionProperties[methodName] = {
"args": methodArgs,
"module": modName,
"calledInModule": []
}
2021-06-26 21:29:49 +00:00
# LOC count for the last function
if lineCount > 2:
lineCount -= 2
if lineCount > 80:
locStr = str(lineCount) + ';' + methodName
if lineCount < 1000:
locStr = '0' + locStr
if lineCount < 100:
locStr = '0' + locStr
if lineCount < 10:
locStr = '0' + locStr
if locStr not in methodLOC:
methodLOC.append(locStr)
break
2021-06-26 19:01:48 +00:00
print('LOC counts:')
methodLOC.sort()
for locStr in methodLOC:
print(locStr.split(';')[0] + ' ' + locStr.split(';')[1])
excludeFuncArgs = [
'pyjsonld'
]
excludeFuncs = [
2020-12-23 12:48:50 +00:00
'link',
'set',
'get'
]
# which modules is each function used within?
2020-12-22 19:28:34 +00:00
for modName, modProperties in modules.items():
2020-12-22 13:04:49 +00:00
print('Module: ' + modName + '')
2020-12-22 19:28:34 +00:00
for name, properties in functionProperties.items():
lineCtr = 0
2020-12-22 19:28:34 +00:00
for line in modules[modName]['lines']:
2020-12-23 12:48:50 +00:00
lineStr = line.strip()
if lineStr.startswith('def '):
lineCtr += 1
continue
if lineStr.startswith('class '):
lineCtr += 1
2020-12-22 19:28:34 +00:00
continue
if name + '(' in line:
modList = \
functionProperties[name]['calledInModule']
if modName not in modList:
modList.append(modName)
if modName in excludeFuncArgs:
lineCtr += 1
continue
if name in excludeFuncs:
lineCtr += 1
continue
callArgs = \
_getFunctionCallArgs(name,
modules[modName]['lines'],
lineCtr)
funcArgs = functionProperties[name]['args']
if not _functionArgsMatch(callArgs, funcArgs):
print('Call to function ' + name +
' does not match its arguments')
print('def args: ' +
str(len(functionProperties[name]['args'])) +
'\n' + str(functionProperties[name]['args']))
print('Call args: ' + str(len(callArgs)) + '\n' +
str(callArgs))
print('module ' + modName + ' line ' + str(lineCtr))
assert False
lineCtr += 1
# don't check these functions, because they are procedurally called
exclusions = [
2020-12-23 12:48:50 +00:00
'do_GET',
'do_POST',
'do_HEAD',
'__run',
'globaltrace',
'localtrace',
'kill',
'clone',
'unregister_rdf_parser',
'set_document_loader',
2020-12-23 12:48:50 +00:00
'has_property',
'has_value',
'add_value',
'get_values',
'remove_property',
'remove_value',
'normalize',
'get_document_loader',
'runInboxQueueWatchdog',
'runInboxQueue',
'runPostSchedule',
'runPostScheduleWatchdog',
'str2bool',
'runNewswireDaemon',
'runNewswireWatchdog',
2021-07-26 17:54:13 +00:00
'runFederatedSharesWatchdog',
'runFederatedSharesDaemon',
'threadSendPost',
'sendToFollowers',
'expireCache',
'getMutualsOfPerson',
'runPostsQueue',
'runSharesExpire',
'runPostsWatchdog',
'runSharesExpireWatchdog',
'getThisWeeksEvents',
'getAvailability',
'_testThreadsFunction',
2021-07-30 19:20:49 +00:00
'createServerGroup',
'createServerAlice',
'createServerBob',
'createServerEve',
'E2EEremoveDevice',
'setOrganizationScheme',
2021-03-04 14:36:24 +00:00
'fill_headers',
'_nothing'
]
2020-12-22 13:57:24 +00:00
excludeImports = [
2020-12-23 12:48:50 +00:00
'link',
'start'
2020-12-22 13:57:24 +00:00
]
excludeLocal = [
'pyjsonld',
'daemon',
'tests'
]
2020-12-23 12:48:50 +00:00
excludeMods = [
'pyjsonld'
]
# check that functions are called somewhere
for name, properties in functionProperties.items():
2020-12-23 12:48:50 +00:00
if name.startswith('__'):
if name.endswith('__'):
continue
if name in exclusions:
continue
2020-12-23 12:48:50 +00:00
if properties['module'] in excludeMods:
continue
2020-12-22 18:20:32 +00:00
isLocalFunction = False
if not properties['calledInModule']:
print('function ' + name +
' in module ' + properties['module'] +
' is not called anywhere')
assert properties['calledInModule']
if len(properties['calledInModule']) == 1:
modName = properties['calledInModule'][0]
if modName not in excludeLocal and \
modName == properties['module']:
2020-12-22 18:20:32 +00:00
isLocalFunction = True
if not name.startswith('_'):
print('Local function ' + name +
' in ' + modName + '.py does not begin with _')
assert False
2020-12-22 13:57:24 +00:00
if name not in excludeImports:
for modName in properties['calledInModule']:
if modName == properties['module']:
continue
importStr = 'from ' + properties['module'] + ' import ' + name
2020-12-22 19:28:34 +00:00
if importStr not in modules[modName]['source']:
2020-12-22 13:57:24 +00:00
print(importStr + ' not found in ' + modName + '.py')
assert False
2020-12-22 18:20:32 +00:00
if not isLocalFunction:
if name.startswith('_'):
excludePublic = [
'pyjsonld',
'daemon',
'tests'
]
modName = properties['module']
if modName not in excludePublic:
print('Public function ' + name + ' in ' +
modName + '.py begins with _')
assert False
2020-12-22 13:04:49 +00:00
print('Function: ' + name + '')
2020-12-23 16:19:18 +00:00
print('Constructing function call graph')
2020-12-23 18:15:30 +00:00
moduleColors = ('red', 'green', 'yellow', 'orange', 'purple', 'cyan',
'darkgoldenrod3', 'darkolivegreen1', 'darkorange1',
'darkorchid1', 'darkseagreen', 'darkslategray4',
'deeppink1', 'deepskyblue1', 'dimgrey', 'gold1',
'goldenrod', 'burlywood2', 'bisque1', 'brown1',
'chartreuse2', 'cornsilk', 'darksalmon')
2020-12-23 17:56:25 +00:00
maxModuleCalls = 1
2020-12-23 19:55:51 +00:00
maxFunctionCalls = 1
2020-12-23 18:15:30 +00:00
colorCtr = 0
2020-12-22 22:55:45 +00:00
for modName, modProperties in modules.items():
lineCtr = 0
2020-12-23 18:15:30 +00:00
modules[modName]['color'] = moduleColors[colorCtr]
colorCtr += 1
if colorCtr >= len(moduleColors):
colorCtr = 0
2020-12-22 22:55:45 +00:00
for line in modules[modName]['lines']:
2020-12-23 12:48:50 +00:00
if line.strip().startswith('def '):
2020-12-22 22:55:45 +00:00
name = line.split('def ')[1].split('(')[0]
callsList = \
getFunctionCalls(name, modules[modName]['lines'],
lineCtr, functionProperties)
functionProperties[name]['calls'] = callsList.copy()
2020-12-23 19:55:51 +00:00
if len(callsList) > maxFunctionCalls:
maxFunctionCalls = len(callsList)
2020-12-23 16:19:18 +00:00
# keep track of which module calls which other module
for fn in callsList:
modCall = functionProperties[fn]['module']
if modCall != modName:
if modules[modName].get('calls'):
if modCall not in modules[modName]['calls']:
modules[modName]['calls'].append(modCall)
2020-12-23 17:56:25 +00:00
if len(modules[modName]['calls']) > \
maxModuleCalls:
maxModuleCalls = \
len(modules[modName]['calls'])
2020-12-23 16:19:18 +00:00
else:
modules[modName]['calls'] = [modCall]
2020-12-22 22:55:45 +00:00
lineCtr += 1
2021-06-26 13:46:22 +00:00
2021-06-26 14:21:24 +00:00
_diagramGroups(['Commandline Interface', 'ActivityPub'], ['utils'],
modules, modGroups, maxModuleCalls)
_diagramGroups(['Commandline Interface', 'Core'], ['utils'],
modules, modGroups, maxModuleCalls)
_diagramGroups(['Timeline', 'Core'], ['utils'],
modules, modGroups, maxModuleCalls)
_diagramGroups(['Web Interface', 'Core'], ['utils'],
2021-06-26 13:46:22 +00:00
modules, modGroups, maxModuleCalls)
2021-06-26 14:21:24 +00:00
_diagramGroups(['Web Interface Columns', 'Core'], ['utils'],
2021-06-26 13:46:22 +00:00
modules, modGroups, maxModuleCalls)
2021-06-26 14:21:24 +00:00
_diagramGroups(['Core'], [],
2021-06-26 13:46:22 +00:00
modules, modGroups, maxModuleCalls)
2021-06-26 14:21:24 +00:00
_diagramGroups(['ActivityPub'], [],
2021-06-26 13:46:22 +00:00
modules, modGroups, maxModuleCalls)
2021-06-26 14:21:24 +00:00
_diagramGroups(['ActivityPub', 'Core'], ['utils'],
2021-06-26 13:46:22 +00:00
modules, modGroups, maxModuleCalls)
2021-06-26 15:57:25 +00:00
_diagramGroups(['ActivityPub', 'Security'], ['utils'],
modules, modGroups, maxModuleCalls)
_diagramGroups(['Core', 'Security'], ['utils'],
modules, modGroups, maxModuleCalls)
_diagramGroups(['Timeline', 'Security'], ['utils'],
modules, modGroups, maxModuleCalls)
2021-06-29 18:06:15 +00:00
_diagramGroups(['Web Interface', 'Accessibility'],
['utils', 'webapp_utils'],
modules, modGroups, maxModuleCalls)
_diagramGroups(['Core', 'Accessibility'], ['utils'],
modules, modGroups, maxModuleCalls)
2020-12-23 16:19:18 +00:00
def _testLinksWithinPost() -> None:
2021-01-02 10:37:19 +00:00
baseDir = os.getcwd()
2021-07-18 09:55:49 +00:00
systemLanguage = 'en'
2021-01-02 10:37:19 +00:00
nickname = 'test27636'
domain = 'rando.site'
port = 443
httpPrefix = 'https'
content = 'This is a test post with links.\n\n' + \
2021-09-10 16:14:50 +00:00
'ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/v4/\n\nhttps://libreserver.org'
2021-05-09 19:11:05 +00:00
followersOnly = False
saveToFile = False
clientToServer = False
commentsEnabled = True
2021-07-01 20:41:17 +00:00
attachImageFilename = None
2021-05-09 19:11:05 +00:00
mediaType = None
imageDescription = None
2021-05-09 19:29:53 +00:00
city = 'London, England'
2021-07-01 20:41:17 +00:00
testInReplyTo = None
testInReplyToAtomUri = None
testSubject = None
testSchedulePost = False
testEventDate = None
testEventTime = None
testLocation = None
testIsArticle = False
2021-08-08 16:52:32 +00:00
conversationId = None
lowBandwidth = True
2021-05-09 19:11:05 +00:00
2021-01-02 10:37:19 +00:00
postJsonObject = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
2021-05-09 19:11:05 +00:00
content, followersOnly, saveToFile,
clientToServer, commentsEnabled,
2021-07-01 20:41:17 +00:00
attachImageFilename, mediaType,
imageDescription, city,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId,
lowBandwidth)
2021-07-01 20:41:17 +00:00
2021-01-02 10:37:19 +00:00
assert postJsonObject['object']['content'] == \
'<p>This is a test post with links.<br><br>' + \
'<a href="ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/v4/" ' + \
'rel="nofollow noopener noreferrer" target="_blank">' + \
'<span class="invisible">ftp://</span>' + \
'<span class="ellipsis">' + \
'ftp.ncdc.noaa.gov/pub/data/ghcn/v4/</span>' + \
2021-09-10 16:14:50 +00:00
'</a><br><br><a href="https://libreserver.org" ' + \
2021-01-02 10:37:19 +00:00
'rel="nofollow noopener noreferrer" target="_blank">' + \
'<span class="invisible">https://</span>' + \
2021-09-10 16:14:50 +00:00
'<span class="ellipsis">libreserver.org</span></a></p>'
assert postJsonObject['object']['content'] == \
postJsonObject['object']['contentMap'][systemLanguage]
2021-01-02 10:37:19 +00:00
2021-01-05 23:09:04 +00:00
content = "<p>Some text</p><p>Other text</p><p>More text</p>" + \
"<pre><code>Errno::EOHNOES (No such file or rodent @ " + \
"ik_right - /tmp/blah.png)<br></code></pre><p>" + \
"(<a href=\"https://welllookeyhere.maam/error.txt\" " + \
"rel=\"nofollow noopener noreferrer\" target=\"_blank\">" + \
"wuh</a>)</p><p>Oh yeah like for sure</p>" + \
"<p>Ground sloth tin opener</p>" + \
"<p><a href=\"https://whocodedthis.huh/tags/" + \
"taggedthing\" class=\"mention hashtag\" rel=\"tag\" " + \
"target=\"_blank\">#<span>taggedthing</span></a></p>"
postJsonObject = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
content,
2021-07-01 20:41:17 +00:00
False, False,
False, True,
None, None,
False, None,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId,
lowBandwidth)
2021-01-05 23:09:04 +00:00
assert postJsonObject['object']['content'] == content
assert postJsonObject['object']['contentMap'][systemLanguage] == content
2021-01-05 23:09:04 +00:00
2021-01-02 10:37:19 +00:00
def _testMastoApi():
2021-01-22 13:32:37 +00:00
print('testMastoApi')
nickname = 'ThisIsATestNickname'
mastoId = getMastoApiV1IdFromNickname(nickname)
assert(mastoId)
nickname2 = getNicknameFromMastoApiV1Id(mastoId)
if nickname2 != nickname:
print(nickname + ' != ' + nickname2)
assert nickname2 == nickname
def _testDomainHandling():
print('testDomainHandling')
testDomain = 'localhost'
assert decodedHost(testDomain) == testDomain
testDomain = '127.0.0.1:60'
assert decodedHost(testDomain) == testDomain
testDomain = '192.168.5.153'
assert decodedHost(testDomain) == testDomain
testDomain = 'xn--espaa-rta.icom.museum'
assert decodedHost(testDomain) == "españa.icom.museum"
def _testPrepareHtmlPostNickname():
2021-02-02 21:08:33 +00:00
print('testPrepareHtmlPostNickname')
postHtml = '<a class="imageAnchor" href="/users/bob?replyfollowers='
postHtml += '<a class="imageAnchor" href="/users/bob?repeatprivate='
result = prepareHtmlPostNickname('alice', postHtml)
assert result == postHtml.replace('/bob?', '/alice?')
postHtml = '<a class="imageAnchor" href="/users/bob?replyfollowers='
postHtml += '<a class="imageAnchor" href="/users/bob;repeatprivate='
expectedHtml = '<a class="imageAnchor" href="/users/alice?replyfollowers='
expectedHtml += '<a class="imageAnchor" href="/users/bob;repeatprivate='
result = prepareHtmlPostNickname('alice', postHtml)
assert result == expectedHtml
def _testValidHashTag():
print('testValidHashTag')
assert validHashTag('ThisIsValid')
assert validHashTag('ThisIsValid12345')
assert validHashTag('ThisIsVälid')
assert validHashTag('यहमान्यहै')
assert not validHashTag('ThisIsNotValid!')
assert not validHashTag('#ThisIsAlsoNotValid')
assert not validHashTag('#यहमान्यहै')
assert not validHashTag('ThisIsAlso&NotValid')
assert not validHashTag('ThisIsAlsoNotValid"')
assert not validHashTag('This Is Also Not Valid"')
assert not validHashTag('This=IsAlsoNotValid"')
def _testMarkdownToHtml():
2021-02-24 20:37:59 +00:00
print('testMarkdownToHtml')
markdown = 'This is just plain text'
assert markdownToHtml(markdown) == markdown
2021-02-26 23:00:06 +00:00
markdown = 'This is a quotation:\n' + \
'> Some quote or other'
assert markdownToHtml(markdown) == 'This is a quotation:<br>' + \
'<blockquote><i>Some quote or other</i></blockquote>'
2021-02-26 23:13:33 +00:00
markdown = 'This is a multi-line quotation:\n' + \
'> The first line\n' + \
'> The second line'
assert markdownToHtml(markdown) == \
'This is a multi-line quotation:<br>' + \
'<blockquote><i>The first line The second line</i></blockquote>'
2021-02-25 10:54:38 +00:00
markdown = 'This is **bold**'
assert markdownToHtml(markdown) == 'This is <b>bold</b>'
markdown = 'This is *italic*'
assert markdownToHtml(markdown) == 'This is <i>italic</i>'
markdown = 'This is _underlined_'
assert markdownToHtml(markdown) == 'This is <ul>underlined</ul>'
markdown = 'This is **just** plain text'
assert markdownToHtml(markdown) == 'This is <b>just</b> plain text'
2021-02-24 20:37:59 +00:00
markdown = '# Title1\n### Title3\n## Title2\n'
assert markdownToHtml(markdown) == \
2021-02-24 21:17:08 +00:00
'<h1>Title1</h1><h3>Title3</h3><h2>Title2</h2>'
2021-02-24 20:37:59 +00:00
markdown = \
2021-02-25 10:54:38 +00:00
'This is [a link](https://something.somewhere) to something.\n' + \
2021-02-26 15:20:43 +00:00
'And [something else](https://cat.pic).\n' + \
'Or ![pounce](/cat.jpg).'
2021-02-24 20:37:59 +00:00
assert markdownToHtml(markdown) == \
'This is <a href="https://something.somewhere" ' + \
'target="_blank" rel="nofollow noopener noreferrer">' + \
2021-02-25 10:54:38 +00:00
'a link</a> to something.<br>' + \
2021-02-24 20:37:59 +00:00
'And <a href="https://cat.pic" ' + \
'target="_blank" rel="nofollow noopener noreferrer">' + \
2021-02-26 15:20:43 +00:00
'something else</a>.<br>' + \
'Or <img class="markdownImage" src="/cat.jpg" alt="pounce" />.'
2021-02-24 20:37:59 +00:00
def _testExtractTextFieldsInPOST():
print('testExtractTextFieldsInPOST')
boundary = '-----------------------------116202748023898664511855843036'
formData = '-----------------------------116202748023898664511855' + \
'843036\r\nContent-Disposition: form-data; name="submitPost"' + \
'\r\n\r\nSubmit\r\n-----------------------------116202748023' + \
'898664511855843036\r\nContent-Disposition: form-data; name=' + \
'"subject"\r\n\r\n\r\n-----------------------------116202748' + \
'023898664511855843036\r\nContent-Disposition: form-data; na' + \
'me="message"\r\n\r\nThis is a ; test\r\n-------------------' + \
'----------116202748023898664511855843036\r\nContent-Disposi' + \
'tion: form-data; name="commentsEnabled"\r\n\r\non\r\n------' + \
'-----------------------116202748023898664511855843036\r\nCo' + \
'ntent-Disposition: form-data; name="eventDate"\r\n\r\n\r\n' + \
'-----------------------------116202748023898664511855843036' + \
'\r\nContent-Disposition: form-data; name="eventTime"\r\n\r' + \
'\n\r\n-----------------------------116202748023898664511855' + \
'843036\r\nContent-Disposition: form-data; name="location"' + \
'\r\n\r\n\r\n-----------------------------116202748023898664' + \
'511855843036\r\nContent-Disposition: form-data; name=' + \
'"imageDescription"\r\n\r\n\r\n-----------------------------' + \
'116202748023898664511855843036\r\nContent-Disposition: ' + \
'form-data; name="attachpic"; filename=""\r\nContent-Type: ' + \
'application/octet-stream\r\n\r\n\r\n----------------------' + \
'-------116202748023898664511855843036--\r\n'
debug = False
fields = extractTextFieldsInPOST(None, boundary, debug, formData)
assert fields['submitPost'] == 'Submit'
assert fields['subject'] == ''
assert fields['commentsEnabled'] == 'on'
assert fields['eventDate'] == ''
assert fields['eventTime'] == ''
assert fields['location'] == ''
assert fields['imageDescription'] == ''
assert fields['message'] == 'This is a ; test'
def _testSpeakerReplaceLinks():
print('testSpeakerReplaceLinks')
text = 'The Tor Project: For Snowflake volunteers: If you use ' + \
'Firefox, Brave, or Chrome, our Snowflake extension turns ' + \
'your browser into a proxy that connects Tor users in ' + \
'censored regions to the Tor network. Note: you should ' + \
'not run more than one snowflake in the same ' + \
'network.https://support.torproject.org/censorship/' + \
'how-to-help-running-snowflake/'
detectedLinks = []
result = speakerReplaceLinks(text, {'Linked': 'Web link'}, detectedLinks)
assert len(detectedLinks) == 1
assert detectedLinks[0] == \
'https://support.torproject.org/censorship/' + \
'how-to-help-running-snowflake/'
assert 'Web link support.torproject.org' in result
def _testCamelCaseSplit():
print('testCamelCaseSplit')
testStr = 'ThisIsCamelCase'
assert camelCaseSplit(testStr) == 'This Is Camel Case'
testStr = 'Notcamelcase test'
assert camelCaseSplit(testStr) == 'Notcamelcase test'
def _testEmojiImages():
2021-03-08 18:47:55 +00:00
print('testEmojiImages')
emojiFilename = 'emoji/default_emoji.json'
assert os.path.isfile(emojiFilename)
emojiJson = loadJson(emojiFilename)
assert emojiJson
for emojiName, emojiImage in emojiJson.items():
emojiImageFilename = 'emoji/' + emojiImage + '.png'
if not os.path.isfile(emojiImageFilename):
print('Missing emoji image ' + emojiName + ' ' +
emojiImage + '.png')
assert os.path.isfile(emojiImageFilename)
def _testExtractPGPPublicKey():
print('testExtractPGPPublicKey')
pubKey = \
2021-03-11 17:15:32 +00:00
'-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n' + \
'mDMEWZBueBYJKwYBBAHaRw8BAQdAKx1t6wL0RTuU6/' + \
'IBjngMbVJJ3Wg/3UW73/PV\n' + \
'I47xKTS0IUJvYiBNb3R0cmFtIDxib2JAZnJlZWRvb' + \
'WJvbmUubmV0PoiQBBMWCAA4\n' + \
'FiEEmruCwAq/OfgmgEh9zCU2GR+nwz8FAlmQbngCG' + \
'wMFCwkIBwMFFQoJCAsFFgID\n' + \
'AQACHgECF4AACgkQzCU2GR+nwz/9sAD/YgsHnVszH' + \
'Nz1zlVc5EgY1ByDupiJpHj0\n' + \
'XsLYk3AbNRgBALn45RqgD4eWHpmOriH09H5Rc5V9i' + \
'N4+OiGUn2AzJ6oHuDgEWZBu\n' + \
'eBIKKwYBBAGXVQEFAQEHQPRBG2ZQJce475S3e0Dxe' + \
'b0Fz5WdEu2q3GYLo4QG+4Ry\n' + \
'AwEIB4h4BBgWCAAgFiEEmruCwAq/OfgmgEh9zCU2G' + \
'R+nwz8FAlmQbngCGwwACgkQ\n' + \
'zCU2GR+nwz+OswD+JOoyBku9FzuWoVoOevU2HH+bP' + \
'OMDgY2OLnST9ZSyHkMBAMcK\n' + \
'fnaZ2Wi050483Sj2RmQRpb99Dod7rVZTDtCqXk0J\n' + \
'=gv5G\n' + \
'-----END PGP PUBLIC KEY BLOCK-----'
testStr = "Some introduction\n\n" + pubKey + "\n\nSome message."
assert containsPGPPublicKey(testStr)
assert not containsPGPPublicKey('String without a pgp key')
result = extractPGPPublicKey(testStr)
assert result
assert result == pubKey
2021-03-17 20:18:00 +00:00
def testUpdateActor():
print('Testing update of actor properties')
global testServerAliceRunning
testServerAliceRunning = False
httpPrefix = 'http'
proxyType = None
federationList = []
baseDir = os.getcwd()
if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests')
os.mkdir(baseDir + '/.tests')
# create the server
aliceDir = baseDir + '/.tests/alice'
aliceDomain = '127.0.0.11'
alicePort = 61792
aliceSendThreads = []
bobAddress = '127.0.0.84:6384'
global thrAlice
if thrAlice:
while thrAlice.is_alive():
thrAlice.stop()
time.sleep(1)
thrAlice.kill()
thrAlice = \
threadWithTrace(target=createServerAlice,
args=(aliceDir, aliceDomain, alicePort, bobAddress,
federationList, False, False,
aliceSendThreads),
daemon=True)
thrAlice.start()
assert thrAlice.is_alive() is True
# wait for server to be running
ctr = 0
while not testServerAliceRunning:
time.sleep(1)
ctr += 1
if ctr > 60:
break
print('Alice online: ' + str(testServerAliceRunning))
print('\n\n*******************************************************')
print('Alice updates her PGP key')
sessionAlice = createSession(proxyType)
cachedWebfingers = {}
personCache = {}
password = 'alicepass'
outboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox'
actorFilename = aliceDir + '/accounts/' + 'alice@' + aliceDomain + '.json'
assert os.path.isfile(actorFilename)
assert len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 0
pubKey = \
'-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n' + \
'mDMEWZBueBYJKwYBBAHaRw8BAQdAKx1t6wL0RTuU6/' + \
'IBjngMbVJJ3Wg/3UW73/PV\n' + \
'I47xKTS0IUJvYiBNb3R0cmFtIDxib2JAZnJlZWRvb' + \
'WJvbmUubmV0PoiQBBMWCAA4\n' + \
'FiEEmruCwAq/OfgmgEh9zCU2GR+nwz8FAlmQbngCG' + \
'wMFCwkIBwMFFQoJCAsFFgID\n' + \
'AQACHgECF4AACgkQzCU2GR+nwz/9sAD/YgsHnVszH' + \
'Nz1zlVc5EgY1ByDupiJpHj0\n' + \
'XsLYk3AbNRgBALn45RqgD4eWHpmOriH09H5Rc5V9i' + \
'N4+OiGUn2AzJ6oHuDgEWZBu\n' + \
'eBIKKwYBBAGXVQEFAQEHQPRBG2ZQJce475S3e0Dxe' + \
'b0Fz5WdEu2q3GYLo4QG+4Ry\n' + \
'AwEIB4h4BBgWCAAgFiEEmruCwAq/OfgmgEh9zCU2G' + \
'R+nwz8FAlmQbngCGwwACgkQ\n' + \
'zCU2GR+nwz+OswD+JOoyBku9FzuWoVoOevU2HH+bP' + \
'OMDgY2OLnST9ZSyHkMBAMcK\n' + \
'fnaZ2Wi050483Sj2RmQRpb99Dod7rVZTDtCqXk0J\n' + \
'=gv5G\n' + \
'-----END PGP PUBLIC KEY BLOCK-----'
signingPrivateKeyPem = None
2021-03-17 20:18:00 +00:00
actorUpdate = \
pgpPublicKeyUpload(aliceDir, sessionAlice,
'alice', password,
aliceDomain, alicePort,
httpPrefix,
cachedWebfingers, personCache,
True, pubKey, signingPrivateKeyPem)
2021-03-17 20:18:00 +00:00
print('actor update result: ' + str(actorUpdate))
assert actorUpdate
# load alice actor
print('Loading actor: ' + actorFilename)
actorJson = loadJson(actorFilename)
assert actorJson
if len(actorJson['attachment']) == 0:
print("actorJson['attachment'] has no contents")
assert len(actorJson['attachment']) > 0
propertyFound = False
for propertyValue in actorJson['attachment']:
if propertyValue['name'] == 'PGP':
print('PGP property set within attachment')
assert pubKey in propertyValue['value']
propertyFound = True
assert propertyFound
# stop the server
thrAlice.kill()
thrAlice.join()
assert thrAlice.is_alive() is False
os.chdir(baseDir)
if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests')
def _testRemovePostInteractions() -> None:
2021-04-30 11:45:46 +00:00
print('testRemovePostInteractions')
postJsonObject = {
"type": "Create",
"object": {
"to": ["#Public"],
"likes": {
"items": ["a", "b", "c"]
},
"replies": {
"replyStuff": ["a", "b", "c"]
},
"shares": {
"sharesStuff": ["a", "b", "c"]
},
"bookmarks": {
"bookmarksStuff": ["a", "b", "c"]
},
"ignores": {
"ignoresStuff": ["a", "b", "c"]
}
}
}
removePostInteractions(postJsonObject, True)
assert postJsonObject['object']['likes']['items'] == []
assert postJsonObject['object']['replies'] == {}
assert postJsonObject['object']['shares'] == {}
assert postJsonObject['object']['bookmarks'] == {}
assert postJsonObject['object']['ignores'] == {}
2021-08-01 19:19:45 +00:00
postJsonObject['object']['to'] = ["some private address"]
2021-04-30 11:45:46 +00:00
assert not removePostInteractions(postJsonObject, False)
def _testSpoofGeolocation() -> None:
2021-05-09 19:11:05 +00:00
print('testSpoofGeolocation')
nogoLine = \
'NEW YORK, USA: 73.951W,40.879, 73.974W,40.83, ' + \
'74.029W,40.756, 74.038W,40.713, 74.056W,40.713, ' + \
'74.127W,40.647, 74.038W,40.629, 73.995W,40.667, ' + \
'74.014W,40.676, 73.994W,40.702, 73.967W,40.699, ' + \
'73.958W,40.729, 73.956W,40.745, 73.918W,40.781, ' + \
'73.937W,40.793, 73.946W,40.782, 73.977W,40.738, ' + \
'73.98W,40.713, 74.012W,40.705, 74.006W,40.752, ' + \
'73.955W,40.824'
polygon = parseNogoString(nogoLine)
assert len(polygon) > 0
assert polygon[0][1] == -73.951
assert polygon[0][0] == 40.879
2021-05-09 19:11:05 +00:00
citiesList = [
2021-05-18 16:58:44 +00:00
'NEW YORK, USA:40.7127281:W74.0060152:784',
'LOS ANGELES, USA:34.0536909:W118.242766:1214',
2021-06-11 09:58:21 +00:00
'SAN FRANCISCO, USA:37.74594738515095:W122.44299445520019:121',
2021-05-18 16:58:44 +00:00
'HOUSTON, USA:29.6072:W95.1586:1553',
2021-06-11 09:58:21 +00:00
'MANCHESTER, ENGLAND:53.4794892:W2.2451148:1276',
2021-05-18 17:46:40 +00:00
'BERLIN, GERMANY:52.5170365:13.3888599:891',
2021-06-08 13:45:43 +00:00
'ANKARA, TURKEY:39.93:32.85:24521',
2021-06-11 11:42:07 +00:00
'LONDON, ENGLAND:51.5073219:W0.1276474:1738',
'SEATTLE, USA:47.59840153253106:W122.31143714060059:217'
2021-05-09 19:11:05 +00:00
]
testSquare = [
[[0.03, 0.01], [0.02, 10], [10.01, 10.02], [10.03, 0.02]]
]
assert pointInNogo(testSquare, 5, 5)
assert pointInNogo(testSquare, 2, 3)
assert not pointInNogo(testSquare, 20, 5)
assert not pointInNogo(testSquare, 11, 6)
assert not pointInNogo(testSquare, 5, -5)
assert not pointInNogo(testSquare, 5, 11)
assert not pointInNogo(testSquare, -5, -5)
assert not pointInNogo(testSquare, -5, 5)
nogoList = []
2021-05-09 19:11:05 +00:00
currTime = datetime.datetime.utcnow()
2021-05-10 13:43:38 +00:00
decoySeed = 7634681
2021-05-10 10:46:45 +00:00
cityRadius = 0.1
coords = spoofGeolocation('', 'los angeles', currTime,
decoySeed, citiesList, nogoList)
2021-05-18 16:58:44 +00:00
assert coords[0] >= 34.0536909 - cityRadius
assert coords[0] <= 34.0536909 + cityRadius
assert coords[1] >= 118.242766 - cityRadius
assert coords[1] <= 118.242766 + cityRadius
2021-05-09 19:11:05 +00:00
assert coords[2] == 'N'
assert coords[3] == 'W'
2021-05-11 12:36:35 +00:00
assert len(coords[4]) > 4
assert len(coords[5]) > 4
assert coords[6] > 0
nogoList = []
2021-05-10 10:46:45 +00:00
coords = spoofGeolocation('', 'unknown', currTime,
decoySeed, citiesList, nogoList)
2021-05-10 10:46:45 +00:00
assert coords[0] >= 51.8744 - cityRadius
assert coords[0] <= 51.8744 + cityRadius
assert coords[1] >= 0.368333 - cityRadius
assert coords[1] <= 0.368333 + cityRadius
2021-05-09 19:29:53 +00:00
assert coords[2] == 'N'
assert coords[3] == 'W'
2021-05-11 12:36:35 +00:00
assert len(coords[4]) == 0
assert len(coords[5]) == 0
assert coords[6] == 0
2021-05-10 13:43:38 +00:00
kmlStr = '<?xml version="1.0" encoding="UTF-8"?>\n'
kmlStr += '<kml xmlns="http://www.opengis.net/kml/2.2">\n'
kmlStr += '<Document>\n'
nogoLine2 = \
'NEW YORK, USA: 74.115W,40.663, 74.065W,40.602, ' + \
'74.118W,40.555, 74.047W,40.516, 73.882W,40.547, ' + \
'73.909W,40.618, 73.978W,40.579, 74.009W,40.602, ' + \
'74.033W,40.61, 74.039W,40.623, 74.032W,40.641, ' + \
'73.996W,40.665'
polygon2 = parseNogoString(nogoLine2)
nogoList = [polygon, polygon2]
2021-05-10 13:43:38 +00:00
for i in range(1000):
dayNumber = randint(10, 30)
hour = randint(1, 23)
hourStr = str(hour)
if hour < 10:
hourStr = '0' + hourStr
2021-07-03 15:59:00 +00:00
dateTimeStr = "2021-05-" + str(dayNumber) + " " + hourStr + ":14"
currTime = datetime.datetime.strptime(dateTimeStr, "%Y-%m-%d %H:%M")
2021-05-18 16:58:44 +00:00
coords = spoofGeolocation('', 'new york, usa', currTime,
decoySeed, citiesList, nogoList)
2021-05-18 16:58:44 +00:00
longitude = coords[1]
if coords[3] == 'W':
longitude = -coords[1]
2021-05-10 13:43:38 +00:00
kmlStr += '<Placemark id="' + str(i) + '">\n'
kmlStr += ' <name>' + str(i) + '</name>\n'
kmlStr += ' <Point>\n'
2021-05-18 16:58:44 +00:00
kmlStr += ' <coordinates>' + str(longitude) + ',' + \
2021-05-10 13:43:38 +00:00
str(coords[0]) + ',0</coordinates>\n'
kmlStr += ' </Point>\n'
kmlStr += '</Placemark>\n'
2021-06-08 13:45:43 +00:00
nogoLine = \
'LONDON, ENGLAND: 0.23888E,51.459, 0.1216E,51.5, ' + \
'0.016E,51.479, 0.097W,51.502, 0.126W,51.482, ' + \
'0.196W,51.457, 0.292W,51.465, 0.309W,51.49, ' + \
'0.226W,51.495, 0.198W,51.47, 0.174W,51.488, ' + \
'0.136W,51.489, 0.1189W,51.515, 0.038E,51.513, ' + \
'0.0692E,51.51, 0.12833E,51.526, 0.3289E,51.475'
polygon = parseNogoString(nogoLine)
nogoLine2 = \
'LONDON, ENGLAND: 0.054W,51.535, 0.044W,51.53, ' + \
'0.008W,51.55, 0.0429W,51.57, 0.038W,51.6, ' + \
'0.0209W,51.603, 0.032W,51.613, 0.00191E,51.66, ' + \
'0.024W,51.666, 0.0313W,51.659, 0.0639W,51.579, ' + \
'0.059W,51.568, 0.0329W,51.552'
polygon2 = parseNogoString(nogoLine2)
nogoList = [polygon, polygon2]
for i in range(1000):
dayNumber = randint(10, 30)
hour = randint(1, 23)
hourStr = str(hour)
if hour < 10:
hourStr = '0' + hourStr
2021-07-03 15:59:00 +00:00
dateTimeStr = "2021-05-" + str(dayNumber) + " " + hourStr + ":14"
currTime = datetime.datetime.strptime(dateTimeStr, "%Y-%m-%d %H:%M")
2021-06-08 13:45:43 +00:00
coords = spoofGeolocation('', 'london, england', currTime,
decoySeed, citiesList, nogoList)
longitude = coords[1]
if coords[3] == 'W':
longitude = -coords[1]
kmlStr += '<Placemark id="' + str(i) + '">\n'
kmlStr += ' <name>' + str(i) + '</name>\n'
kmlStr += ' <Point>\n'
kmlStr += ' <coordinates>' + str(longitude) + ',' + \
str(coords[0]) + ',0</coordinates>\n'
kmlStr += ' </Point>\n'
kmlStr += '</Placemark>\n'
2021-06-11 09:58:21 +00:00
nogoLine = \
2021-06-11 11:42:07 +00:00
'SAN FRANCISCO, USA: 121.988W,37.408, 121.924W,37.452, ' + \
'121.951W,37.498, 121.992W,37.505, 122.056W,37.54, ' + \
'122.077W,37.578, 122.098W,37.618, 122.131W,37.637, ' + \
'122.189W,37.706, 122.227W,37.775, 122.279W,37.798, ' + \
'122.315W,37.802, 122.291W,37.832, 122.309W,37.902, ' + \
'122.382W,37.915, 122.368W,37.927, 122.514W,37.882, ' + \
'122.473W,37.83, 122.481W,37.788, 122.394W,37.796, ' + \
'122.384W,37.729, 122.4W,37.688, 122.382W,37.654, ' + \
'122.406W,37.637, 122.392W,37.612, 122.356W,37.586, ' + \
'122.332W,37.586, 122.275W,37.529, 122.228W,37.488, ' + \
'122.181W,37.482, 122.134W,37.48, 122.128W,37.471, ' + \
'122.122W,37.448, 122.095W,37.428, 122.07W,37.413, ' + \
'122.036W,37.402, 122.035W,37.421'
2021-06-11 09:58:21 +00:00
polygon = parseNogoString(nogoLine)
nogoLine2 = \
2021-06-11 11:42:07 +00:00
'SAN FRANCISCO, USA: 122.446W,37.794, 122.511W,37.778, ' + \
'122.51W,37.771, 122.454W,37.775, 122.452W,37.766, ' + \
'122.510W,37.763, 122.506W,37.735, 122.498W,37.733, ' + \
'122.496W,37.729, 122.491W,37.729, 122.475W,37.73, ' + \
'122.474W,37.72, 122.484W,37.72, 122.485W,37.703, ' + \
'122.495W,37.702, 122.493W,37.679, 122.486W,37.667, ' + \
'122.492W,37.664, 122.493W,37.629, 122.456W,37.625, ' + \
'122.450W,37.617, 122.455W,37.621, 122.41W,37.586, ' + \
'122.383W,37.561, 122.335W,37.509, 122.655W,37.48, ' + \
'122.67W,37.9, 122.272W,37.93, 122.294W,37.801, ' + \
'122.448W,37.804'
2021-06-11 09:58:21 +00:00
polygon2 = parseNogoString(nogoLine2)
nogoList = [polygon, polygon2]
for i in range(1000):
dayNumber = randint(10, 30)
hour = randint(1, 23)
hourStr = str(hour)
if hour < 10:
hourStr = '0' + hourStr
2021-07-03 15:59:00 +00:00
dateTimeStr = "2021-05-" + str(dayNumber) + " " + hourStr + ":14"
currTime = datetime.datetime.strptime(dateTimeStr, "%Y-%m-%d %H:%M")
2021-06-11 09:58:21 +00:00
coords = spoofGeolocation('', 'SAN FRANCISCO, USA', currTime,
decoySeed, citiesList, nogoList)
longitude = coords[1]
if coords[3] == 'W':
longitude = -coords[1]
kmlStr += '<Placemark id="' + str(i) + '">\n'
kmlStr += ' <name>' + str(i) + '</name>\n'
kmlStr += ' <Point>\n'
kmlStr += ' <coordinates>' + str(longitude) + ',' + \
str(coords[0]) + ',0</coordinates>\n'
kmlStr += ' </Point>\n'
kmlStr += '</Placemark>\n'
2021-06-11 11:42:07 +00:00
nogoLine = \
'SEATTLE, USA: 122.247W,47.918, 122.39W,47.802, ' + \
'122.389W,47.769, 122.377W,47.758, 122.371W,47.726, ' + \
'122.379W,47.706, 122.4W,47.696, 122.405W,47.673, ' + \
'122.416W,47.65, 122.414W,47.642, 122.391W,47.632, ' + \
'122.373W,47.633, 122.336W,47.602, 122.288W,47.501, ' + \
'122.299W,47.503, 122.386W,47.592, 122.412W,47.574, ' + \
'122.394W,47.549, 122.388W,47.507, 122.35W,47.481, ' + \
'122.365W,47.459, 122.33W,47.406, 122.323W,47.392, ' + \
'122.321W,47.346, 122.441W,47.302, 122.696W,47.085, ' + \
'122.926W,47.066, 122.929W,48.383'
polygon = parseNogoString(nogoLine)
nogoLine2 = \
'SEATTLE, USA: 122.267W,47.758, 122.29W,47.471, ' + \
'122.272W,47.693, 122.256W,47.672, 122.278W,47.652, ' + \
'122.29W,47.583, 122.262W,47.548, 122.265W,47.52, ' + \
'122.218W,47.498, 122.194W,47.501, 122.193W,47.55, ' + \
'122.173W,47.58, 122.22W,47.617, 122.238W,47.617, ' + \
'122.239W,47.637, 122.2W,47.644, 122.207W,47.703, ' + \
'122.22W,47.705, 122.231W,47.699, 122.255W,47.751'
polygon2 = parseNogoString(nogoLine2)
nogoLine3 = \
'SEATTLE, USA: 122.347W,47.675, 122.344W,47.681, ' + \
'122.337W,47.685, 122.324W,47.679, 122.331W,47.677, ' + \
'122.34W,47.669, 122.34W,47.664, 122.348W,47.665'
polygon3 = parseNogoString(nogoLine3)
nogoLine4 = \
'SEATTLE, USA: 122.423W,47.669, 122.345W,47.641, ' + \
'122.34W,47.625, 122.327W,47.626, 122.274W,47.64, ' + \
'122.268W,47.654, 122.327W,47.654, 122.336W,47.647, ' + \
'122.429W,47.684'
polygon4 = parseNogoString(nogoLine4)
nogoList = [polygon, polygon2, polygon3, polygon4]
for i in range(1000):
dayNumber = randint(10, 30)
hour = randint(1, 23)
hourStr = str(hour)
if hour < 10:
hourStr = '0' + hourStr
2021-07-03 15:59:00 +00:00
dateTimeStr = "2021-05-" + str(dayNumber) + " " + hourStr + ":14"
currTime = datetime.datetime.strptime(dateTimeStr, "%Y-%m-%d %H:%M")
2021-06-11 11:42:07 +00:00
coords = spoofGeolocation('', 'SEATTLE, USA', currTime,
decoySeed, citiesList, nogoList)
longitude = coords[1]
if coords[3] == 'W':
longitude = -coords[1]
kmlStr += '<Placemark id="' + str(i) + '">\n'
kmlStr += ' <name>' + str(i) + '</name>\n'
kmlStr += ' <Point>\n'
kmlStr += ' <coordinates>' + str(longitude) + ',' + \
str(coords[0]) + ',0</coordinates>\n'
kmlStr += ' </Point>\n'
kmlStr += '</Placemark>\n'
2021-05-10 13:43:38 +00:00
kmlStr += '</Document>\n'
kmlStr += '</kml>'
2021-06-22 12:27:10 +00:00
with open('unittest_decoy.kml', 'w+') as kmlFile:
kmlFile.write(kmlStr)
2021-05-09 19:11:05 +00:00
def _testSkills() -> None:
2021-05-13 14:13:27 +00:00
print('testSkills')
actorJson = {
2021-05-16 15:10:39 +00:00
'hasOccupation': [
{
'@type': 'Occupation',
'name': "Sysop",
2021-05-17 10:27:14 +00:00
"occupationLocation": {
"@type": "City",
"name": "Fediverse"
2021-05-17 09:12:10 +00:00
},
2021-05-16 15:10:39 +00:00
'skills': []
}
]
2021-05-13 14:13:27 +00:00
}
skillsDict = {
'bakery': 40,
'gardening': 70
}
setSkillsFromDict(actorJson, skillsDict)
2021-05-16 15:10:39 +00:00
assert actorHasSkill(actorJson, 'bakery')
assert actorHasSkill(actorJson, 'gardening')
assert actorSkillValue(actorJson, 'bakery') == 40
assert actorSkillValue(actorJson, 'gardening') == 70
2021-05-13 14:13:27 +00:00
def _testRoles() -> None:
print('testRoles')
actorJson = {
2021-05-16 15:10:39 +00:00
'hasOccupation': [
{
'@type': 'Occupation',
'name': "Sysop",
2021-05-17 10:27:14 +00:00
'occupationLocation': {
'@type': 'City',
'name': 'Fediverse'
2021-05-17 09:12:10 +00:00
},
2021-05-16 15:10:39 +00:00
'skills': []
}
]
}
testRolesList = ["admin", "moderator"]
setRolesFromList(actorJson, testRolesList)
2021-05-16 15:10:39 +00:00
assert actorHasRole(actorJson, "admin")
assert actorHasRole(actorJson, "moderator")
assert not actorHasRole(actorJson, "editor")
assert not actorHasRole(actorJson, "counselor")
2021-05-17 16:13:56 +00:00
assert not actorHasRole(actorJson, "artist")
2021-06-20 15:45:29 +00:00
def _testUserAgentDomain() -> None:
print('testUserAgentDomain')
userAgent = \
'http.rb/4.4.1 (Mastodon/9.10.11; +https://mastodon.something/)'
assert userAgentDomain(userAgent, False) == 'mastodon.something'
userAgent = \
'Mozilla/70.0 (X11; Linux x86_64; rv:1.0) Gecko/20450101 Firefox/1.0'
assert userAgentDomain(userAgent, False) is None
2021-07-06 16:29:03 +00:00
def _testSwitchWords() -> None:
print('testSwitchWords')
rules = [
"rock -> hamster",
"orange -> lemon"
]
baseDir = os.getcwd()
nickname = 'testuser'
domain = 'testdomain.com'
content = 'This is a test'
result = switchWords(baseDir, nickname, domain, content, rules)
assert result == content
content = 'This is orange test'
result = switchWords(baseDir, nickname, domain, content, rules)
assert result == 'This is lemon test'
content = 'This is a test rock'
result = switchWords(baseDir, nickname, domain, content, rules)
assert result == 'This is a test hamster'
def _testLimitWordLengths() -> None:
print('testLimitWordLengths')
maxWordLength = 13
text = "This is a test"
result = limitWordLengths(text, maxWordLength)
assert result == text
text = "This is an exceptionallylongword test"
result = limitWordLengths(text, maxWordLength)
assert result == "This is an exceptionally test"
def _testLimitRepetedWords() -> None:
print('limitRepeatedWords')
text = \
"This is a preamble.\n\n" + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same\n\n" + \
"Some other text."
expected = \
"This is a preamble.\n\n" + \
"Same Same Same Same Same Same\n\n" + \
"Some other text."
result = limitRepeatedWords(text, 6)
assert result == expected
text = \
"This is other preamble.\n\n" + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same " + \
"Same Same Same Same Same Same Same Same Same Same"
expected = \
"This is other preamble.\n\n" + \
"Same Same Same Same Same Same"
result = limitRepeatedWords(text, 6)
assert result == expected
2021-07-19 10:07:29 +00:00
def _testSetActorLanguages():
print('testSetActorLanguages')
actorJson = {
"attachment": []
}
setActorLanguages(None, actorJson, 'es, fr, en')
2021-07-19 10:07:29 +00:00
assert len(actorJson['attachment']) == 1
assert actorJson['attachment'][0]['name'] == 'Languages'
assert actorJson['attachment'][0]['type'] == 'PropertyValue'
2021-08-11 09:15:46 +00:00
assert isinstance(actorJson['attachment'][0]['value'], str)
assert ',' in actorJson['attachment'][0]['value']
langList = getActorLanguagesList(actorJson)
assert 'en' in langList
assert 'fr' in langList
assert 'es' in langList
languagesStr = getActorLanguages(actorJson)
assert languagesStr == 'en / es / fr'
2021-07-19 10:07:29 +00:00
2021-07-20 10:45:04 +00:00
def _testGetLinksFromContent():
print('testGetLinksFromContent')
content = 'This text has no links'
links = getLinksFromContent(content)
assert not links
link1 = 'https://somewebsite.net'
link2 = 'http://somewhere.or.other'
content = \
2021-07-20 18:02:42 +00:00
'This is <a href="' + link1 + '">@linked</a>. ' + \
2021-07-20 10:45:04 +00:00
'And <a href="' + link2 + '">another</a>.'
links = getLinksFromContent(content)
assert len(links.items()) == 2
2021-07-20 18:02:42 +00:00
assert links.get('@linked')
assert links['@linked'] == link1
assert links.get('another')
assert links['another'] == link2
2021-07-20 10:45:04 +00:00
2021-07-20 18:02:42 +00:00
contentPlain = '<p>' + removeHtml(content) + '</p>'
2021-07-20 18:04:36 +00:00
assert '>@linked</a>' not in contentPlain
2021-07-20 18:02:42 +00:00
content = addLinksToContent(contentPlain, links)
assert '>@linked</a>' in content
2021-07-20 10:45:04 +00:00
def _testAuthorizeSharedItems():
print('testAuthorizeSharedItems')
sharedItemsFederatedDomains = \
['dog.domain', 'cat.domain', 'birb.domain']
tokensJson = \
generateSharedItemFederationTokens(sharedItemsFederatedDomains, None)
2021-07-26 12:20:07 +00:00
tokensJson = \
createSharedItemFederationToken(None, 'cat.domain', False, tokensJson)
assert tokensJson
2021-07-26 12:20:07 +00:00
assert not tokensJson.get('dog.domain')
assert tokensJson.get('cat.domain')
2021-07-26 12:20:07 +00:00
assert not tokensJson.get('birb.domain')
assert len(tokensJson['dog.domain']) == 0
assert len(tokensJson['cat.domain']) >= 64
2021-07-26 12:20:07 +00:00
assert len(tokensJson['birb.domain']) == 0
assert not authorizeSharedItems(sharedItemsFederatedDomains, None,
'birb.domain',
2021-07-26 12:20:07 +00:00
'cat.domain', 'M' * 86,
False, tokensJson)
assert authorizeSharedItems(sharedItemsFederatedDomains, None,
'birb.domain',
2021-07-26 12:20:07 +00:00
'cat.domain', tokensJson['cat.domain'],
False, tokensJson)
2021-07-26 12:20:07 +00:00
tokensJson = \
updateSharedItemFederationToken(None,
2021-08-05 11:24:24 +00:00
'dog.domain', 'testToken',
True, tokensJson)
2021-07-26 12:20:07 +00:00
assert tokensJson['dog.domain'] == 'testToken'
# the shared item federation list changes
sharedItemsFederatedDomains = \
['possum.domain', 'cat.domain', 'birb.domain']
tokensJson = mergeSharedItemTokens(None, '',
sharedItemsFederatedDomains,
tokensJson)
assert 'dog.domain' not in tokensJson
assert 'cat.domain' in tokensJson
assert len(tokensJson['cat.domain']) >= 64
assert 'birb.domain' in tokensJson
assert 'possum.domain' in tokensJson
assert len(tokensJson['birb.domain']) == 0
assert len(tokensJson['possum.domain']) == 0
2021-07-28 09:35:21 +00:00
def _testDateConversions() -> None:
print('testDateConversions')
dateStr = "2021-05-16T14:37:41Z"
dateSec = dateStringToSeconds(dateStr)
dateStr2 = dateSecondsToString(dateSec)
assert dateStr == dateStr2
2021-07-29 14:15:44 +00:00
def _testValidPassword():
print('testValidPassword')
assert not validPassword('123')
assert not validPassword('')
assert validPassword('パスワード12345')
assert validPassword('测试密码12345')
assert validPassword('A!bc:defg1/234?56')
2021-08-07 17:03:41 +00:00
def _testGetPriceFromString() -> None:
print('testGetPriceFromString')
price, curr = getPriceFromString("5.23")
assert price == "5.23"
assert curr == "EUR"
price, curr = getPriceFromString("£7.36")
assert price == "7.36"
assert curr == "GBP"
price, curr = getPriceFromString("$10.63")
assert price == "10.63"
assert curr == "USD"
2021-08-08 11:16:18 +00:00
def _translateOntology() -> None:
baseDir = os.getcwd()
ontologyTypes = getCategoryTypes(baseDir)
2021-08-08 11:16:18 +00:00
url = 'https://translate.astian.org'
apiKey = None
ltLangList = libretranslateLanguages(url, apiKey)
baseDir = os.getcwd()
languagesStr = getSupportedLanguages(baseDir)
assert languagesStr
for oType in ontologyTypes:
changed = False
filename = baseDir + '/ontology/' + oType + 'Types.json'
if not os.path.isfile(filename):
continue
ontologyJson = loadJson(filename)
if not ontologyJson:
continue
index = -1
for item in ontologyJson['@graph']:
index += 1
if "rdfs:label" not in item:
continue
englishStr = None
languagesFound = []
for label in item["rdfs:label"]:
if '@language' not in label:
continue
languagesFound.append(label['@language'])
if '@value' not in label:
continue
if label['@language'] == 'en':
englishStr = label['@value']
if not englishStr:
continue
for lang in languagesStr:
if lang not in languagesFound:
translatedStr = None
if url and lang in ltLangList:
translatedStr = \
libretranslate(url, englishStr, 'en', lang, apiKey)
if not translatedStr:
translatedStr = englishStr
else:
translatedStr = translatedStr.replace('<p>', '')
translatedStr = translatedStr.replace('</p>', '')
ontologyJson['@graph'][index]["rdfs:label"].append({
"@value": translatedStr,
"@language": lang
})
changed = True
if not changed:
continue
saveJson(ontologyJson, filename + '.new')
2021-09-08 20:12:03 +00:00
def _testCanReplyTo() -> None:
print('testCanReplyTo')
baseDir = os.getcwd()
systemLanguage = 'en'
nickname = 'test27637'
domain = 'rando.site'
port = 443
httpPrefix = 'https'
content = 'This is a test post with links.\n\n' + \
2021-09-10 16:14:50 +00:00
'ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/v4/\n\nhttps://libreserver.org'
2021-09-08 20:12:03 +00:00
followersOnly = False
saveToFile = False
clientToServer = False
commentsEnabled = True
attachImageFilename = None
mediaType = None
imageDescription = None
city = 'London, England'
testInReplyTo = None
testInReplyToAtomUri = None
testSubject = None
testSchedulePost = False
testEventDate = None
testEventTime = None
testLocation = None
testIsArticle = False
conversationId = None
lowBandwidth = True
postJsonObject = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
content, followersOnly, saveToFile,
clientToServer, commentsEnabled,
attachImageFilename, mediaType,
imageDescription, city,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId,
lowBandwidth)
# set the date on the post
currDateStr = "2021-09-08T20:45:00Z"
postJsonObject['published'] = currDateStr
postJsonObject['object']['published'] = currDateStr
2021-09-08 20:13:41 +00:00
# test a post within the reply interval
2021-09-08 20:12:03 +00:00
postUrl = postJsonObject['object']['id']
replyIntervalHours = 2
currDateStr = "2021-09-08T21:32:10Z"
assert canReplyTo(baseDir, nickname, domain,
postUrl, replyIntervalHours,
currDateStr,
postJsonObject)
2021-09-08 20:13:41 +00:00
# test a post outside of the reply interval
2021-09-08 20:12:03 +00:00
currDateStr = "2021-09-09T09:24:47Z"
assert not canReplyTo(baseDir, nickname, domain,
postUrl, replyIntervalHours,
currDateStr,
postJsonObject)
2019-06-30 21:20:02 +00:00
def runAllTests():
print('Running tests...')
updateDefaultThemesList(os.getcwd())
2021-08-08 11:16:18 +00:00
_translateOntology()
2021-08-07 17:03:41 +00:00
_testGetPriceFromString()
2021-07-28 09:35:21 +00:00
_testFunctions()
2021-09-08 20:12:03 +00:00
_testCanReplyTo()
2021-07-28 09:35:21 +00:00
_testDateConversions()
_testAuthorizeSharedItems()
2021-07-20 20:39:26 +00:00
_testValidPassword()
2021-07-20 10:45:04 +00:00
_testGetLinksFromContent()
2021-07-19 10:07:29 +00:00
_testSetActorLanguages()
_testLimitRepetedWords()
_testLimitWordLengths()
2021-07-06 16:29:03 +00:00
_testSwitchWords()
2021-06-20 15:45:29 +00:00
_testUserAgentDomain()
_testRoles()
_testSkills()
_testSpoofGeolocation()
_testRemovePostInteractions()
_testExtractPGPPublicKey()
_testEmojiImages()
_testCamelCaseSplit()
_testSpeakerReplaceLinks()
_testExtractTextFieldsInPOST()
_testMarkdownToHtml()
_testValidHashTag()
_testPrepareHtmlPostNickname()
_testDomainHandling()
_testMastoApi()
_testLinksWithinPost()
_testReplyToPublicPost()
_testGetMentionedPeople()
_testGuessHashtagCategory()
_testValidNickname()
_testParseFeedDate()
_testFirstParagraphFromString()
_testGetNewswireTags()
_testHashtagRuleTree()
_testRemoveHtmlTag()
_testReplaceEmailQuote()
_testConstantTimeStringCheck()
_testTranslations()
_testValidContentWarning()
_testRemoveIdEnding()
_testJsonPostAllowsComments()
_runHtmlReplaceQuoteMarks()
_testDangerousCSS()
_testDangerousMarkup()
_testRemoveHtml()
_testSiteIsActive()
_testJsonld()
_testRemoveTextFormatting()
_testWebLinks()
_testRecentPostsCache()
_testTheme()
_testSaveLoadJson()
_testJsonString()
_testGetStatusNumber()
_testAddEmoji()
_testActorParsing()
_testHttpsig()
2021-09-01 16:35:24 +00:00
_testHttpSignedGET()
_testHttpSigNew()
_testCache()
_testThreads()
_testCreatePerson()
_testAuthentication()
_testFollowersOfPerson()
_testNoOfFollowersOnDomain()
_testFollows()
_testGroupFollowers()
2020-03-22 21:16:02 +00:00
print('Tests succeeded\n')