From eb44a660663910e965c33d3913a9a67b24883df1 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 23 Nov 2020 09:39:09 +0000 Subject: [PATCH 001/233] Check for system accounts during authorization --- daemon.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/daemon.py b/daemon.py index 7ffaba474..96b34b5d5 100644 --- a/daemon.py +++ b/daemon.py @@ -1120,21 +1120,22 @@ class PubServer(BaseHTTPRequestHandler): tokenStr = tokenStr.split(';')[0].strip() if self.server.tokensLookup.get(tokenStr): nickname = self.server.tokensLookup[tokenStr] - self.authorizedNickname = nickname - # default to the inbox of the person - if self.path == '/': - self.path = '/users/' + nickname + '/inbox' - # check that the path contains the same nickname - # as the cookie otherwise it would be possible - # to be authorized to use an account you don't own - if '/' + nickname + '/' in self.path: - return True - elif '/' + nickname + '?' in self.path: - return True - elif self.path.endswith('/' + nickname): - return True - print('AUTH: nickname ' + nickname + - ' was not found in path ' + self.path) + if not isSystemAccount(nickname): + self.authorizedNickname = nickname + # default to the inbox of the person + if self.path == '/': + self.path = '/users/' + nickname + '/inbox' + # check that the path contains the same nickname + # as the cookie otherwise it would be possible + # to be authorized to use an account you don't own + if '/' + nickname + '/' in self.path: + return True + elif '/' + nickname + '?' in self.path: + return True + elif self.path.endswith('/' + nickname): + return True + print('AUTH: nickname ' + nickname + + ' was not found in path ' + self.path) return False print('AUTH: epicyon cookie ' + 'authorization failed, header=' + From fdc05e987a4d8d71254701d8d0ed1b6350768d0d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 23 Nov 2020 09:41:54 +0000 Subject: [PATCH 002/233] Comments --- daemon.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/daemon.py b/daemon.py index 96b34b5d5..111e2908e 100644 --- a/daemon.py +++ b/daemon.py @@ -1145,13 +1145,13 @@ class PubServer(BaseHTTPRequestHandler): return False print('AUTH: Header cookie was not authorized') return False - # basic auth + # basic auth for c2s if self.headers.get('Authorization'): if authorize(self.server.baseDir, self.path, self.headers['Authorization'], self.server.debug): return True - print('AUTH: Basic auth did not authorize ' + + print('AUTH: C2S Basic auth did not authorize ' + self.headers['Authorization']) return False From 99abc1f1f47f18abd660f459a65287fa6332258e Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 23 Nov 2020 09:51:26 +0000 Subject: [PATCH 003/233] Check for system account logins via c2s --- auth.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/auth.py b/auth.py index 021a17b61..e21d58a46 100644 --- a/auth.py +++ b/auth.py @@ -11,6 +11,7 @@ import hashlib import binascii import os import secrets +from utils import isSystemAccount def hashPassword(password: str) -> str: @@ -85,7 +86,7 @@ def authorizeBasic(baseDir: str, path: str, authHeader: str, """ if ' ' not in authHeader: if debug: - print('DEBUG: Authorixation header does not ' + + print('DEBUG: basic auth - Authorixation header does not ' + 'contain a space character') return False if '/users/' not in path and \ @@ -93,23 +94,32 @@ def authorizeBasic(baseDir: str, path: str, authHeader: str, '/channel/' not in path and \ '/profile/' not in path: if debug: - print('DEBUG: Path for Authorization does not contain a user') + print('DEBUG: basic auth - ' + + 'path for Authorization does not contain a user') return False pathUsersSection = path.split('/users/')[1] if '/' not in pathUsersSection: if debug: - print('DEBUG: This is not a users endpoint') + print('DEBUG: basic auth - this is not a users endpoint') return False nicknameFromPath = pathUsersSection.split('/')[0] + if isSystemAccount(nicknameFromPath): + print('basic auth - attempted login using system account ' + + nicknameFromPath + ' in path') + return False base64Str = \ authHeader.split(' ')[1].replace('\n', '').replace('\r', '') plain = base64.b64decode(base64Str).decode('utf-8') if ':' not in plain: if debug: - print('DEBUG: Basic Auth header does not contain a ":" ' + + print('DEBUG: basic Auth header does not contain a ":" ' + 'separator for username:password') return False nickname = plain.split(':')[0] + if isSystemAccount(nickname): + print('basic auth - attempted login using system account ' + nickname + + ' in Auth header') + return False if nickname != nicknameFromPath: if debug: print('DEBUG: Nickname given in the path (' + nicknameFromPath + From 901d9c66c5df0006f0773c192dfec1df35ec0476 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 23 Nov 2020 10:18:52 +0000 Subject: [PATCH 004/233] Lower case --- auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth.py b/auth.py index e21d58a46..f0124f550 100644 --- a/auth.py +++ b/auth.py @@ -112,7 +112,7 @@ def authorizeBasic(baseDir: str, path: str, authHeader: str, plain = base64.b64decode(base64Str).decode('utf-8') if ':' not in plain: if debug: - print('DEBUG: basic Auth header does not contain a ":" ' + + print('DEBUG: basic auth header does not contain a ":" ' + 'separator for username:password') return False nickname = plain.split(':')[0] From 44eacde556aac2421b9e87bf2f8701d6ff0cf71f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 23 Nov 2020 14:26:20 +0000 Subject: [PATCH 005/233] Checking that petname exists --- petnames.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/petnames.py b/petnames.py index 7046a5d94..305f1d591 100644 --- a/petnames.py +++ b/petnames.py @@ -29,7 +29,7 @@ def setPetName(baseDir: str, nickname: str, domain: str, if os.path.isfile(petnamesFilename): with open(petnamesFilename, 'r') as petnamesFile: petnamesStr = petnamesFile.read() - if entry in petnamesStr: + if petnamesStr.startswith(petname + ' '): return True if ' ' + handle + '\n' in petnamesStr: petnamesList = petnamesStr.split('\n') From ddb11903d473262b04765a28fc5b93916b97be74 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 23 Nov 2020 15:07:55 +0000 Subject: [PATCH 006/233] Create default petname when following --- petnames.py | 2 +- tests.py | 8 +++++++- utils.py | 38 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/petnames.py b/petnames.py index 305f1d591..7046a5d94 100644 --- a/petnames.py +++ b/petnames.py @@ -29,7 +29,7 @@ def setPetName(baseDir: str, nickname: str, domain: str, if os.path.isfile(petnamesFilename): with open(petnamesFilename, 'r') as petnamesFile: petnamesStr = petnamesFile.read() - if petnamesStr.startswith(petname + ' '): + if entry in petnamesStr: return True if ' ' + handle + '\n' in petnamesStr: petnamesList = petnamesStr.split('\n') diff --git a/tests.py b/tests.py index 4b86d499d..e42a6c930 100644 --- a/tests.py +++ b/tests.py @@ -1387,6 +1387,8 @@ def testClientToServer(): httpPrefix, cachedWebfingers, personCache, True, __version__) + alicePetnamesFilename = aliceDir + '/accounts/' + \ + 'alice@' + aliceDomain + '/petnames.txt' aliceFollowingFilename = \ aliceDir + '/accounts/alice@' + aliceDomain + '/following.txt' bobFollowersFilename = \ @@ -1395,7 +1397,8 @@ def testClientToServer(): if os.path.isfile(bobFollowersFilename): if 'alice@' + aliceDomain + ':' + str(alicePort) in \ open(bobFollowersFilename).read(): - if os.path.isfile(aliceFollowingFilename): + if os.path.isfile(aliceFollowingFilename) and \ + os.path.isfile(alicePetnamesFilename): if 'bob@' + bobDomain + ':' + str(bobPort) in \ open(aliceFollowingFilename).read(): break @@ -1403,6 +1406,9 @@ def testClientToServer(): assert os.path.isfile(bobFollowersFilename) assert os.path.isfile(aliceFollowingFilename) + assert os.path.isfile(alicePetnamesFilename) + assert 'bob bob@' + bobDomain in \ + open(alicePetnamesFilename).read() print('alice@' + aliceDomain + ':' + str(alicePort) + ' in ' + bobFollowersFilename) assert 'alice@' + aliceDomain + ':' + str(alicePort) in \ diff --git a/utils.py b/utils.py index 3bd40da77..8607c4c63 100644 --- a/utils.py +++ b/utils.py @@ -522,6 +522,37 @@ def getDomainFromActor(actor: str) -> (str, int): return domain, port +def setDefaultPetName(baseDir: str, nickname: str, domain: str, + followNickname: str, followDomain: str) -> None: + """Sets a default petname + This helps especially when using onion or i2p address + """ + if ':' in domain: + domain = domain.split(':')[0] + userPath = baseDir + '/accounts/' + nickname + '@' + domain + petnamesFilename = userPath + '/petnames.txt' + + petnameLookupEntry = followNickname + ' ' + \ + followNickname + '@' + followDomain + '\n' + if not os.path.isfile(petnamesFilename): + # if there is no existing petnames lookup file + with open(petnamesFilename, 'w+') as petnamesFile: + petnamesFile.write(petnameLookupEntry) + return + + with open(petnamesFilename, 'r') as petnamesFile: + petnamesStr = petnamesFile.read() + if petnamesStr: + petnamesList = petnamesStr.split('\n') + for pet in petnamesList: + if pet.startswith(followNickname + ' '): + # petname already exists + return + # petname doesn't already exist + with open(petnamesFilename, 'a+') as petnamesFile: + petnamesFile.write(petnameLookupEntry) + + def followPerson(baseDir: str, nickname: str, domain: str, followNickname: str, followDomain: str, federationList: [], debug: bool, @@ -593,9 +624,9 @@ def followPerson(baseDir: str, nickname: str, domain: str, with open(filename, 'w+') as f: f.write(handleToFollow + '\n') - # Default to adding new follows to the calendar. - # Possibly this could be made optional if followFile.endswith('following.txt'): + # Default to adding new follows to the calendar. + # Possibly this could be made optional # if following a person add them to the list of # calendar follows print('DEBUG: adding ' + @@ -603,6 +634,9 @@ def followPerson(baseDir: str, nickname: str, domain: str, nickname + '@' + domain) addPersonToCalendar(baseDir, nickname, domain, followNickname, followDomain) + # add a default petname + setDefaultPetName(baseDir, nickname, domain, + followNickname, followDomain) return True From ca94076cf46036727c12ef00823269b6df07747f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 23 Nov 2020 21:12:41 +0000 Subject: [PATCH 007/233] Modern theme changes --- theme/indymediamodern/left_col_image.png | Bin 9369 -> 9442 bytes theme/indymediamodern/theme.json | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/theme/indymediamodern/left_col_image.png b/theme/indymediamodern/left_col_image.png index fdf06cfd59feba7289970506e351f1454cc330ec..fd2241cd5f76db6e96c327d23fd7b1cbf93c923b 100644 GIT binary patch delta 9431 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ⅈ$x@*1^7qYxgO&1{MReoK9B_XrS0fK+>#X?xW#}1JR4`8FO5oJ31YIb zT#Yky1v40gXT9JUHrDqK&z^~%S?_k@k8N@4z zNb@ou%y=}M$M%`=gi#URGN1rM;>PU=+uFY(38JV5ZSlyV!sNw2lj>4~P8zGQ66Y1kc!GV5p$+t#NE~W0KVe<1Ldfg<}pK zQGbb115cv}Ws)}rt0Q1wD=6P!tr9kBhH51))GU{sBFMuGlo}|ILP3Usoq)YDj=(j; zQdn4oOHqYzIhMs`7HDK(0r(-N9QMX;%v8D|AjJ{DFVwCulET>r6ktIN`MUvcBsAM7 z!N`bFZSV;C8&H5xV#ZzbWXtM{x93?JhkqqN9|vQ`-Ol8jmMa^QTLIuJK&;WwR{&oD zbaB8}0DlJX6`%^+0Q-Ff@D;#UfGWHM_zIA+$TV=GrvSxOM*&hd1)(tpGk#mcKr&?s zCm}2!AHhe`;1UBNU%6*RWgN!TT>=`$y~X{$0#t1UIOr=t)mDH5z5*l@8u&ASKW+o~ z3Q&a=ppmZt{tV#T099520tu*0>?=SLAzky{Vig?r6(D(#seGG=Do!EaSAeQ)0#;H5 zNY%}t9BhFV*A{ojxji2~eE9I;BewWI?ceLZP-_4H00K!wK~ym01lp}A00000NkvXX Hu0mjfRdu93 diff --git a/theme/indymediamodern/theme.json b/theme/indymediamodern/theme.json index d9570b5c7..49082a703 100644 --- a/theme/indymediamodern/theme.json +++ b/theme/indymediamodern/theme.json @@ -52,7 +52,7 @@ "container-button-padding": "0px", "container-button-margin": "0px", "column-left-icon-size": "15%", - "column-right-icon-size": "8%", + "column-right-icon-size": "9.5%", "button-margin": "2px", "button-height-padding": "5px", "icon-brightness-change": "70%", @@ -64,8 +64,8 @@ "login-button-color": "#25408f", "login-button-fg-color": "white", "column-left-width": "10vw", - "column-center-width": "70vw", - "column-right-width": "20vw", + "column-center-width": "75vw", + "column-right-width": "15vw", "column-right-fg-color": "#25408f", "column-right-fg-color-voted-on": "red", "newswire-item-moderated-color": "red", From 5d2b45560e6e626260fb137e339dd470378b35fd Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 10:53:10 +0000 Subject: [PATCH 008/233] Unit test for valid nickname --- tests.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests.py b/tests.py index e42a6c930..aae2345b3 100644 --- a/tests.py +++ b/tests.py @@ -32,6 +32,7 @@ from follow import clearFollows from follow import clearFollowers from follow import sendFollowRequestViaServer from follow import sendUnfollowRequestViaServer +from utils import validNickname from utils import firstParagraphFromString from utils import removeIdEnding from utils import siteIsActive @@ -2403,8 +2404,26 @@ def testParseFeedDate(): assert publishedDate == "2020-11-22 18:51:33+00:00" +def testValidNickname(): + 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 runAllTests(): print('Running tests...') + testValidNickname() testParseFeedDate() testFirstParagraphFromString() testGetNewswireTags() From fef671bef28af1a355776e8562fb0c435446dac2 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 12:02:53 +0000 Subject: [PATCH 009/233] News actor preferredUsername --- person.py | 1 - 1 file changed, 1 deletion(-) diff --git a/person.py b/person.py index 9bd2ce695..770873832 100644 --- a/person.py +++ b/person.py @@ -236,7 +236,6 @@ def createPersonBase(baseDir: str, nickname: str, domain: str, port: int, elif nickname == 'news': personUrl = httpPrefix + '://' + domain + \ '/about/more?news_actor=true' - personName = originalDomain approveFollowers = True personType = 'Application' From 3c9ce0a6dafd802555d8bcc02c0b26558ade183e Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 12:19:35 +0000 Subject: [PATCH 010/233] Profile image --- person.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/person.py b/person.py index 770873832..93c49014e 100644 --- a/person.py +++ b/person.py @@ -484,7 +484,8 @@ def createPerson(baseDir: str, nickname: str, domain: str, port: int, defaultProfileImageFilename = baseDir + '/theme/default/image.png' if theme: if os.path.isfile(baseDir + '/theme/' + theme + '/image.png'): - defaultBannerFilename = baseDir + '/theme/' + theme + '/image.png' + defaultProfileImageFilename = \ + baseDir + '/theme/' + theme + '/image.png' if os.path.isfile(defaultProfileImageFilename): copyfile(defaultProfileImageFilename, baseDir + '/accounts/' + nickname + '@' + domain + '/image.png') From 36dad532dfe6ab1a081c3991e9b2b53202e0b71f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 12:24:30 +0000 Subject: [PATCH 011/233] Comment --- utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/utils.py b/utils.py index 8607c4c63..82989bb50 100644 --- a/utils.py +++ b/utils.py @@ -969,6 +969,7 @@ def validNickname(domain: str, nickname: str) -> bool: for c in forbiddenChars: if c in nickname: return False + # this should only apply for the shared inbox if nickname == domain: return False reservedNames = ('inbox', 'dm', 'outbox', 'following', From c002adccc62ccb339e7fbe9e2e7cb04351cc33cb Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 12:42:33 +0000 Subject: [PATCH 012/233] Creating the news account --- person.py | 59 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/person.py b/person.py index 93c49014e..f41950a3b 100644 --- a/person.py +++ b/person.py @@ -436,10 +436,16 @@ def createPerson(baseDir: str, nickname: str, domain: str, port: int, # If a config.json file doesn't exist then don't decrement # remaining registrations counter - remainingConfigExists = getConfigParam(baseDir, 'registrationsRemaining') - if remainingConfigExists: - registrationsRemaining = int(remainingConfigExists) - if registrationsRemaining <= 0: + if nickname != 'news': + remainingConfigExists = \ + getConfigParam(baseDir, 'registrationsRemaining') + if remainingConfigExists: + registrationsRemaining = int(remainingConfigExists) + if registrationsRemaining <= 0: + return None, None, None, None + else: + if os.path.isdir(baseDir + '/accounts/news@' + domain): + # news account already exists return None, None, None, None (privateKeyPem, publicKeyPem, @@ -450,12 +456,13 @@ def createPerson(baseDir: str, nickname: str, domain: str, port: int, manualFollowerApproval, password) if not getConfigParam(baseDir, 'admin'): - # print(nickname+' becomes the instance admin and a moderator') - setConfigParam(baseDir, 'admin', nickname) - setRole(baseDir, nickname, domain, 'instance', 'admin') - setRole(baseDir, nickname, domain, 'instance', 'moderator') - setRole(baseDir, nickname, domain, 'instance', 'editor') - setRole(baseDir, nickname, domain, 'instance', 'delegator') + if nickname != 'news': + # print(nickname+' becomes the instance admin and a moderator') + setConfigParam(baseDir, 'admin', nickname) + setRole(baseDir, nickname, domain, 'instance', 'admin') + setRole(baseDir, nickname, domain, 'instance', 'moderator') + setRole(baseDir, nickname, domain, 'instance', 'editor') + setRole(baseDir, nickname, domain, 'instance', 'delegator') if not os.path.isdir(baseDir + '/accounts'): os.mkdir(baseDir + '/accounts') @@ -469,18 +476,28 @@ def createPerson(baseDir: str, nickname: str, domain: str, port: int, fFile.write('\n') # notify when posts are liked - notifyLikesFilename = baseDir + '/accounts/' + \ - nickname + '@' + domain + '/.notifyLikes' - with open(notifyLikesFilename, 'w+') as nFile: - nFile.write('\n') + if nickname != 'news': + notifyLikesFilename = baseDir + '/accounts/' + \ + nickname + '@' + domain + '/.notifyLikes' + with open(notifyLikesFilename, 'w+') as nFile: + nFile.write('\n') - if os.path.isfile(baseDir + '/img/default-avatar.png'): - copyfile(baseDir + '/img/default-avatar.png', - baseDir + '/accounts/' + nickname + '@' + domain + - '/avatar.png') theme = getConfigParam(baseDir, 'theme') if not theme: theme = 'default' + + if nickname != 'news': + if os.path.isfile(baseDir + '/img/default-avatar.png'): + copyfile(baseDir + '/img/default-avatar.png', + baseDir + '/accounts/' + nickname + '@' + domain + + '/avatar.png') + else: + newsAvatar = baseDir + '/theme/' + theme + '/icons/avatar_news.png' + if os.path.isfile(newsAvatar): + copyfile(newsAvatar, + baseDir + '/accounts/' + nickname + '@' + domain + + '/avatar.png') + defaultProfileImageFilename = baseDir + '/theme/default/image.png' if theme: if os.path.isfile(baseDir + '/theme/' + theme + '/image.png'): @@ -496,7 +513,7 @@ def createPerson(baseDir: str, nickname: str, domain: str, port: int, if os.path.isfile(defaultBannerFilename): copyfile(defaultBannerFilename, baseDir + '/accounts/' + nickname + '@' + domain + '/banner.png') - if remainingConfigExists: + if nickname != 'news' and remainingConfigExists: registrationsRemaining -= 1 setConfigParam(baseDir, 'registrationsRemaining', str(registrationsRemaining)) @@ -516,8 +533,8 @@ def createNewsInbox(baseDir: str, domain: str, port: int, httpPrefix: str) -> (str, str, {}, {}): """Generates the news inbox """ - return createPersonBase(baseDir, 'news', domain, port, httpPrefix, - True, True, None) + return createPerson(baseDir, 'news', domain, port, + httpPrefix, True, True, None) def personUpgradeActor(baseDir: str, personJson: {}, From 28d57f492b1f75747e7284b9f6af9dddcd295b65 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 13:05:44 +0000 Subject: [PATCH 013/233] Don't show license icon on news front page --- webapp_profile.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/webapp_profile.py b/webapp_profile.py index 1e5d2acfd..870b5e1a6 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -627,11 +627,13 @@ def htmlProfile(rssIconAtTop: bool, bannerFile, bannerFilename = \ getBannerFile(baseDir, nickname, domain) - licenseStr = \ - '' + \ - '' + \
-        translate['Get the source code'] + '' + licenseStr = '' + if not isSystemAccount(nickname): + licenseStr = \ + '' + \ + '' + \
+            translate['Get the source code'] + '' if selected == 'posts': profileStr += \ From 5fbc000eea5aff0d4640f8530f7565d8da8d5dc9 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 14:06:42 +0000 Subject: [PATCH 014/233] Tidying --- roles.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/roles.py b/roles.py index fe60b2ab3..22db327b3 100644 --- a/roles.py +++ b/roles.py @@ -46,15 +46,20 @@ def clearEditorStatus(baseDir: str) -> None: for f in os.scandir(directory): f = f.name filename = os.fsdecode(f) - if filename.endswith(".json") and '@' in filename: - filename = os.path.join(baseDir + '/accounts/', filename) - if '"editor"' in open(filename).read(): - actorJson = loadJson(filename) - if actorJson: - if actorJson['roles'].get('instance'): - if 'editor' in actorJson['roles']['instance']: - actorJson['roles']['instance'].remove('editor') - saveJson(actorJson, filename) + if '@' not in filename: + continue + if not filename.endswith(".json"): + continue + filename = os.path.join(baseDir + '/accounts/', filename) + if '"editor"' not in open(filename).read(): + continue + actorJson = loadJson(filename) + if not actorJson: + continue + if actorJson['roles'].get('instance'): + if 'editor' in actorJson['roles']['instance']: + actorJson['roles']['instance'].remove('editor') + saveJson(actorJson, filename) def addModerator(baseDir: str, nickname: str, domain: str) -> None: From 6011031b51d8eae14cd779fd5e00ff0994a747ce Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 14:49:07 +0000 Subject: [PATCH 015/233] Link to the button header --- webapp_profile.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp_profile.py b/webapp_profile.py index 870b5e1a6..eae41fa8c 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -772,7 +772,7 @@ def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str, profileStr += \ '
\n' + \ ' ' + \
@@ -792,7 +792,7 @@ def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
             profileStr += \
                 '  <center>\n' + \
                 '    <a href=' + \

From 56fdc81fae92c78df13869eb50d10083b5d3ef3b Mon Sep 17 00:00:00 2001
From: Bob Mottram <bob@freedombone.net>
Date: Tue, 24 Nov 2020 17:35:33 +0000
Subject: [PATCH 016/233] Translations for roles

---
 translations/ar.json | 6 +++++-
 translations/ca.json | 6 +++++-
 translations/cy.json | 6 +++++-
 translations/de.json | 6 +++++-
 translations/en.json | 6 +++++-
 translations/es.json | 6 +++++-
 translations/fr.json | 6 +++++-
 translations/ga.json | 6 +++++-
 translations/hi.json | 6 +++++-
 translations/it.json | 6 +++++-
 translations/ja.json | 6 +++++-
 translations/oc.json | 6 +++++-
 translations/pt.json | 6 +++++-
 translations/ru.json | 6 +++++-
 translations/zh.json | 6 +++++-
 webapp_profile.py    | 8 ++++++--
 16 files changed, 81 insertions(+), 17 deletions(-)

diff --git a/translations/ar.json b/translations/ar.json
index b94660914..ac34087ef 100644
--- a/translations/ar.json
+++ b/translations/ar.json
@@ -330,5 +330,9 @@
     \n

' + project + \ '

\n
\n' for role in rolesList: - profileStr += '

' + role + '

\n' + if translate.get(role): + profileStr += '

' + translate[role] + '

\n' + else: + profileStr += '

' + role + '

\n' profileStr += '
\n' if len(profileStr) == 0: profileStr += \ From 77323ddc6938faa6a79160dc7ce61d319a4a5b67 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 18:00:29 +0000 Subject: [PATCH 017/233] Consistant link style --- epicyon-blog.css | 13 ++++++++++++- epicyon-calendar.css | 13 +++++++++++++ epicyon-follow.css | 13 ++++++++++++- epicyon-links.css | 6 ++++-- epicyon-login.css | 13 ++++++++++++- epicyon-options.css | 13 ++++++++++++- epicyon-profile.css | 7 ++++--- epicyon-search.css | 6 ++++-- epicyon-suspended.css | 13 ++++++++++++- 9 files changed, 85 insertions(+), 12 deletions(-) diff --git a/epicyon-blog.css b/epicyon-blog.css index 277a9710a..b3176f2b6 100644 --- a/epicyon-blog.css +++ b/epicyon-blog.css @@ -45,6 +45,7 @@ --focus-color: white; --line-spacing: 130%; --header-font: 'Bedstead'; + --main-link-color-hover: #bbb; } @font-face { @@ -82,12 +83,22 @@ a, u { a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); - font-weight: bold; + font-weight: normal; } a:link { color: var(--main-link-color); background: var(--link-bg-color); + font-weight: normal; +} + +a:link:hover { + color: var(--main-link-color-hover); + font-weight: bold; +} + +a:visited:hover { + color: var(--main-link-color-hover); font-weight: bold; } diff --git a/epicyon-calendar.css b/epicyon-calendar.css index c51568bbe..cdf5145f5 100644 --- a/epicyon-calendar.css +++ b/epicyon-calendar.css @@ -23,6 +23,7 @@ --font-size-calendar-cell-mobile: 4rem; --calendar-header-font: 'Montserrat'; --calendar-header-font-style: italic; + --main-link-color-hover: #bbb; } @font-face { @@ -59,6 +60,7 @@ a:visited{ z-index: 1; padding: 1rem; margin: -1rem; + font-weight: normal; } a:link { @@ -67,6 +69,17 @@ a:link { z-index: 1; padding: 1rem; margin: -1rem; + font-weight: normal; +} + +a:link:hover { + color: var(--main-link-color-hover); + font-weight: bold; +} + +a:visited:hover { + color: var(--main-link-color-hover); + font-weight: bold; } a:focus { diff --git a/epicyon-follow.css b/epicyon-follow.css index 1e255985d..f7423cd99 100644 --- a/epicyon-follow.css +++ b/epicyon-follow.css @@ -31,6 +31,7 @@ --follow-text-size2: 40px; --follow-text-entry-width: 90%; --focus-color: white; + --main-link-color-hover: #bbb; } @font-face { @@ -66,12 +67,22 @@ a, u { a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); - font-weight: bold; + font-weight: normal; } a:link { color: var(--main-link-color); background: var(--link-bg-color); + font-weight: normal; +} + +a:link:hover { + color: var(--main-link-color-hover); + font-weight: bold; +} + +a:visited:hover { + color: var(--main-link-color-hover); font-weight: bold; } diff --git a/epicyon-links.css b/epicyon-links.css index 8cc051baa..90901fe10 100644 --- a/epicyon-links.css +++ b/epicyon-links.css @@ -154,20 +154,22 @@ a, u { a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); - font-weight: bold; + font-weight: normal; } a:link { color: var(--main-link-color); background: var(--link-bg-color); - font-weight: bold; + font-weight: normal; } a:link:hover { + font-weight: bold; color: var(--main-link-color-hover); } a:visited:hover { + font-weight: bold; color: var(--main-link-color-hover); } diff --git a/epicyon-login.css b/epicyon-login.css index 8d55f72b9..367f539c2 100644 --- a/epicyon-login.css +++ b/epicyon-login.css @@ -22,6 +22,7 @@ --focus-color: white; --line-spacing: 130%; --login-logo-width: 20%; + --main-link-color-hover: #bbb; } @font-face { @@ -65,12 +66,22 @@ a, u { a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); - font-weight: bold; + font-weight: normal; } a:link { color: var(--main-link-color); background: var(--link-bg-color); + font-weight: normal; +} + +a:link:hover { + color: var(--main-link-color-hover); + font-weight: bold; +} + +a:visited:hover { + color: var(--main-link-color-hover); font-weight: bold; } diff --git a/epicyon-options.css b/epicyon-options.css index 330f108cf..fadcd39ed 100644 --- a/epicyon-options.css +++ b/epicyon-options.css @@ -34,6 +34,7 @@ --follow-text-entry-width: 90%; --focus-color: white; --petname-width-chars: 16ch; + --main-link-color-hover: #bbb; } @font-face { @@ -74,12 +75,22 @@ a, u { a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); - font-weight: bold; + font-weight: normal; } a:link { color: var(--main-link-color); background: var(--link-bg-color); + font-weight: normal; +} + +a:link:hover { + color: var(--main-link-color-hover); + font-weight: bold; +} + +a:visited:hover { + color: var(--main-link-color-hover); font-weight: bold; } diff --git a/epicyon-profile.css b/epicyon-profile.css index caef0e4d0..f20b31764 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -263,20 +263,21 @@ a, u { color: var(--main-fg-color); } -a:visited{ +a:visited { color: var(--main-visited-color); background: var(--link-bg-color); - font-weight: bold; + font-weight: normal; } a:link { color: var(--main-link-color); background: var(--link-bg-color); - font-weight: bold; + font-weight: normal; } a:link:hover { color: var(--main-link-color-hover); + font-weight: bold; } a:visited:hover { diff --git a/epicyon-search.css b/epicyon-search.css index 16ae3fb4b..5b49e78e3 100644 --- a/epicyon-search.css +++ b/epicyon-search.css @@ -76,21 +76,23 @@ a, u { a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); - font-weight: bold; + font-weight: normal; } a:link { color: var(--main-link-color); background: var(--link-bg-color); - font-weight: bold; + font-weight: normal; } a:link:hover { + font-weight: bold; color: var(--main-link-color-hover); } a:visited:hover { color: var(--main-link-color-hover); + font-weight: bold; } a:focus { diff --git a/epicyon-suspended.css b/epicyon-suspended.css index 4a5d03304..f0ba55626 100644 --- a/epicyon-suspended.css +++ b/epicyon-suspended.css @@ -20,6 +20,7 @@ --button-background: #999; --button-selected: #666; --focus-color: white; + --main-link-color-hover: #bbb; } @font-face { @@ -56,12 +57,22 @@ a, u { a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); - font-weight: bold; + font-weight: normal; } a:link { color: var(--main-link-color); background: var(--link-bg-color); + font-weight: normal; +} + +a:link:hover { + color: var(--main-link-color-hover); + font-weight: bold; +} + +a:visited:hover { + color: var(--main-link-color-hover); font-weight: bold; } From facef454768dfd1cc976c21f5d3726ee08d082b0 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 18:03:09 +0000 Subject: [PATCH 018/233] Stay normal while hovering --- epicyon-blog.css | 2 -- epicyon-calendar.css | 2 -- epicyon-follow.css | 2 -- epicyon-links.css | 2 -- epicyon-login.css | 2 -- epicyon-options.css | 2 -- epicyon-profile.css | 1 - epicyon-search.css | 2 -- epicyon-suspended.css | 2 -- 9 files changed, 17 deletions(-) diff --git a/epicyon-blog.css b/epicyon-blog.css index b3176f2b6..5833bacb2 100644 --- a/epicyon-blog.css +++ b/epicyon-blog.css @@ -94,12 +94,10 @@ a:link { a:link:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:visited:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:focus { diff --git a/epicyon-calendar.css b/epicyon-calendar.css index cdf5145f5..076d5ad1f 100644 --- a/epicyon-calendar.css +++ b/epicyon-calendar.css @@ -74,12 +74,10 @@ a:link { a:link:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:visited:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:focus { diff --git a/epicyon-follow.css b/epicyon-follow.css index f7423cd99..47f3db384 100644 --- a/epicyon-follow.css +++ b/epicyon-follow.css @@ -78,12 +78,10 @@ a:link { a:link:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:visited:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:focus { diff --git a/epicyon-links.css b/epicyon-links.css index 90901fe10..0552ddf93 100644 --- a/epicyon-links.css +++ b/epicyon-links.css @@ -164,12 +164,10 @@ a:link { } a:link:hover { - font-weight: bold; color: var(--main-link-color-hover); } a:visited:hover { - font-weight: bold; color: var(--main-link-color-hover); } diff --git a/epicyon-login.css b/epicyon-login.css index 367f539c2..e63ed535e 100644 --- a/epicyon-login.css +++ b/epicyon-login.css @@ -77,12 +77,10 @@ a:link { a:link:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:visited:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:focus { diff --git a/epicyon-options.css b/epicyon-options.css index fadcd39ed..3bd8c6ab0 100644 --- a/epicyon-options.css +++ b/epicyon-options.css @@ -86,12 +86,10 @@ a:link { a:link:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:visited:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:focus { diff --git a/epicyon-profile.css b/epicyon-profile.css index f20b31764..6de5e493f 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -277,7 +277,6 @@ a:link { a:link:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:visited:hover { diff --git a/epicyon-search.css b/epicyon-search.css index 5b49e78e3..444c8a264 100644 --- a/epicyon-search.css +++ b/epicyon-search.css @@ -86,13 +86,11 @@ a:link { } a:link:hover { - font-weight: bold; color: var(--main-link-color-hover); } a:visited:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:focus { diff --git a/epicyon-suspended.css b/epicyon-suspended.css index f0ba55626..7d46feb7c 100644 --- a/epicyon-suspended.css +++ b/epicyon-suspended.css @@ -68,12 +68,10 @@ a:link { a:link:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:visited:hover { color: var(--main-link-color-hover); - font-weight: bold; } a:focus { From 13714d905cfe2faa8518414cd0a79948ac4f5c10 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 18:24:46 +0000 Subject: [PATCH 019/233] Too many dashes --- epicyon-profile.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/epicyon-profile.css b/epicyon-profile.css index 6de5e493f..b21f573a2 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -284,7 +284,7 @@ a:visited:hover { } .buttonevent:hover { - filter: brightness(var(----icon-brightness-change)); + filter: brightness(var(--icon-brightness-change)); } a:focus { @@ -631,7 +631,7 @@ a:focus { } .containericons img:hover { - filter: brightness(var(----icon-brightness-change)); + filter: brightness(var(--icon-brightness-change)); } .post-title { From 9855787ad25c6bae9a528e10d6dc3b82c07bfde4 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 18:29:31 +0000 Subject: [PATCH 020/233] Icon hover brightness for left and right columns --- epicyon-profile.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/epicyon-profile.css b/epicyon-profile.css index b21f573a2..b6c6ac397 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -1067,6 +1067,9 @@ div.container { float: left; width: var(--column-left-width); } + .col-left img:hover { + filter: brightness(var(--icon-brightness-change)); + } .col-left img.leftColEdit { background: var(--column-left-color); width: var(--column-left-icon-size); @@ -1112,6 +1115,9 @@ div.container { width: var(--column-right-width); overflow: hidden; } + .col-right img:hover { + filter: brightness(var(--icon-brightness-change)); + } .col-right img.rightColEdit { background: var(--column-left-color); width: var(--column-right-icon-size); From a55b74721440e4ca4c9b41e7d3d01cebdda3dd7a Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 18:32:06 +0000 Subject: [PATCH 021/233] Extra peertube site --- webapp_media.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp_media.py b/webapp_media.py index e551624d3..7d53565c3 100644 --- a/webapp_media.py +++ b/webapp_media.py @@ -103,7 +103,7 @@ def addEmbeddedVideoFromSites(translate: {}, content: str, 'tube.piweb.be', 'pe.ertu.be', 'peertube.social', 'videos.lescommuns.org', 'peertube.nogafa.org', 'skeptikon.fr', 'video.tedomum.net', - 'tube.p2p.legal', + 'tube.p2p.legal', 'tilvids.com', 'sikke.fi', 'exode.me', 'peertube.video') for site in peerTubeSites: if '"https://' + site in content: From 73f0525176967536670eaf63de2aa405cbe0dca9 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 19:48:55 +0000 Subject: [PATCH 022/233] css tidying --- epicyon-profile.css | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/epicyon-profile.css b/epicyon-profile.css index b6c6ac397..de0fa62ce 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -317,8 +317,6 @@ a:focus { .profileHeader * { -webkit-box-sizing: border-box; box-sizing: border-box; - -webkit-transition: all 0.25s ease; - transition: all 0.25s ease; } .profileHeader img.profileBackground { @@ -437,17 +435,7 @@ a:focus { cursor: pointer; display: inline-block; position: relative; - transition: 0.5s; -} - -.button span:after { - font-family: var(--header-font); - content: '\00bb'; - position: absolute; - opacity: 0; - top: 0; - right: -20px; - transition: 0.5s; + transition: 2.0s; } .button:hover { @@ -465,17 +453,7 @@ a:focus { cursor: pointer; display: inline-block; position: relative; - transition: 0.5s; -} - -.buttonselected span:after { - font-family: var(--header-font); - content: '\00bb'; - position: absolute; - opacity: 0; - top: 0; - right: -20px; - transition: 0.5s; + transition: 2.0s; } .buttonselected:hover { @@ -940,14 +918,6 @@ div.gallery img { li { list-style:none;} /***********BUTTON CODE ******************************************************/ -a, button, input:focus, input[type='button'], input[type='reset'], input[type='submit'], textarea:focus, .button { - -webkit-transition: all 0.1s ease-in-out; - -moz-transition: all 0.1s ease-in-out; - -ms-transition: all 0.1s ease-in-out; - -o-transition: all 0.1s ease-in-out; - transition: all 0.1s ease-in-out; - text-decoration: none; -} .btn { margin: -3px 0 0 0; } From f8aabec732fd64b5d22cb384f0aff5872f3b4b9f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 24 Nov 2020 20:02:15 +0000 Subject: [PATCH 023/233] Undecorated links --- epicyon-blog.css | 2 ++ epicyon-follow.css | 2 ++ epicyon-links.css | 2 ++ epicyon-login.css | 2 ++ epicyon-options.css | 2 ++ epicyon-profile.css | 2 ++ epicyon-search.css | 2 ++ epicyon-suspended.css | 2 ++ 8 files changed, 16 insertions(+) diff --git a/epicyon-blog.css b/epicyon-blog.css index 5833bacb2..8d3d34f08 100644 --- a/epicyon-blog.css +++ b/epicyon-blog.css @@ -84,12 +84,14 @@ a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link { color: var(--main-link-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link:hover { diff --git a/epicyon-follow.css b/epicyon-follow.css index 47f3db384..8007cbd11 100644 --- a/epicyon-follow.css +++ b/epicyon-follow.css @@ -68,12 +68,14 @@ a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link { color: var(--main-link-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link:hover { diff --git a/epicyon-links.css b/epicyon-links.css index 0552ddf93..c72c899e4 100644 --- a/epicyon-links.css +++ b/epicyon-links.css @@ -155,12 +155,14 @@ a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link { color: var(--main-link-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link:hover { diff --git a/epicyon-login.css b/epicyon-login.css index e63ed535e..4315a3708 100644 --- a/epicyon-login.css +++ b/epicyon-login.css @@ -67,12 +67,14 @@ a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link { color: var(--main-link-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link:hover { diff --git a/epicyon-options.css b/epicyon-options.css index 3bd8c6ab0..eca2187c1 100644 --- a/epicyon-options.css +++ b/epicyon-options.css @@ -76,12 +76,14 @@ a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link { color: var(--main-link-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link:hover { diff --git a/epicyon-profile.css b/epicyon-profile.css index de0fa62ce..5d42811f3 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -267,12 +267,14 @@ a:visited { color: var(--main-visited-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link { color: var(--main-link-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link:hover { diff --git a/epicyon-search.css b/epicyon-search.css index 444c8a264..9fdeb1371 100644 --- a/epicyon-search.css +++ b/epicyon-search.css @@ -77,12 +77,14 @@ a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link { color: var(--main-link-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link:hover { diff --git a/epicyon-suspended.css b/epicyon-suspended.css index 7d46feb7c..716c3c42a 100644 --- a/epicyon-suspended.css +++ b/epicyon-suspended.css @@ -58,12 +58,14 @@ a:visited{ color: var(--main-visited-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link { color: var(--main-link-color); background: var(--link-bg-color); font-weight: normal; + text-decoration: none; } a:link:hover { From a8365bfaea1beb72367788245c9789473e430922 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 25 Nov 2020 11:02:40 +0000 Subject: [PATCH 024/233] More efficient checking for blocked hashtags --- webapp_hashtagswarm.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/webapp_hashtagswarm.py b/webapp_hashtagswarm.py index e26a8bd3f..e51506661 100644 --- a/webapp_hashtagswarm.py +++ b/webapp_hashtagswarm.py @@ -7,7 +7,6 @@ __email__ = "bob@freedombone.net" __status__ = "Production" import os -from blocking import isBlockedHashtag from datetime import datetime @@ -81,6 +80,12 @@ def htmlHashTagSwarm(baseDir: str, actor: str, translate: {}) -> str: tagSwarm = [] domainHistogram = {} + blockedStr = '' + globalBlockingFilename = baseDir + '/accounts/blocking.txt' + if os.path.isfile(globalBlockingFilename): + with open(globalBlockingFilename, 'r') as fp: + blockedStr = fp.read() + for subdir, dirs, files in os.walk(baseDir + '/tags'): for f in files: tagsFilename = os.path.join(baseDir + '/tags', f) @@ -98,7 +103,7 @@ def htmlHashTagSwarm(baseDir: str, actor: str, translate: {}) -> str: continue hashTagName = f.split('.')[0] - if isBlockedHashtag(baseDir, hashTagName): + if '#' + hashTagName + '\n' in blockedStr: continue with open(tagsFilename, 'r') as fp: # only read one line, which saves time and memory @@ -129,6 +134,7 @@ def htmlHashTagSwarm(baseDir: str, actor: str, translate: {}) -> str: postDomain = postUrl.split('##')[1] if '#' in postDomain: postDomain = postDomain.split('#')[0] + if domainHistogram.get(postDomain): domainHistogram[postDomain] = \ domainHistogram[postDomain] + 1 From 04ab7c67d88d684e066b3d9067ca221b1bb7dbd2 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 25 Nov 2020 11:09:16 +0000 Subject: [PATCH 025/233] Comments --- webapp_hashtagswarm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/webapp_hashtagswarm.py b/webapp_hashtagswarm.py index e51506661..b07d739d9 100644 --- a/webapp_hashtagswarm.py +++ b/webapp_hashtagswarm.py @@ -80,6 +80,8 @@ def htmlHashTagSwarm(baseDir: str, actor: str, translate: {}) -> str: tagSwarm = [] domainHistogram = {} + # Load the blocked hashtags into memory. + # This avoids needing to repeatedly load the blocked file for each hashtag blockedStr = '' globalBlockingFilename = baseDir + '/accounts/blocking.txt' if os.path.isfile(globalBlockingFilename): From 4227ab94deb9e975b2dbc02de8a8f117ef1bbd16 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 25 Nov 2020 11:11:03 +0000 Subject: [PATCH 026/233] Debug --- daemon.py | 1 + 1 file changed, 1 insertion(+) diff --git a/daemon.py b/daemon.py index 111e2908e..b473c9812 100644 --- a/daemon.py +++ b/daemon.py @@ -4931,6 +4931,7 @@ class PubServer(BaseHTTPRequestHandler): if '?page=' in hashtag: hashtag = hashtag.split('?page=')[0] if isBlockedHashtag(baseDir, hashtag): + print('BLOCK: hashtag #' + hashtag) msg = htmlHashtagBlocked(self.server.cssCache, baseDir, self.server.translate).encode('utf-8') self._login_headers('text/html', len(msg), callingDomain) From 3f119d2e1f47a1d30e959e7d37beaaab2745b01b Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 25 Nov 2020 11:22:36 +0000 Subject: [PATCH 027/233] Unquote hashtag --- daemon.py | 1 + 1 file changed, 1 insertion(+) diff --git a/daemon.py b/daemon.py index b473c9812..156b4b9fe 100644 --- a/daemon.py +++ b/daemon.py @@ -4930,6 +4930,7 @@ class PubServer(BaseHTTPRequestHandler): hashtag = path.split('/tags/')[1] if '?page=' in hashtag: hashtag = hashtag.split('?page=')[0] + hashtag = urllib.parse.unquote_plus(hashtag) if isBlockedHashtag(baseDir, hashtag): print('BLOCK: hashtag #' + hashtag) msg = htmlHashtagBlocked(self.server.cssCache, baseDir, From ee42e3c8987d2563e9ddd1853e2e7cc4f216aac2 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 25 Nov 2020 13:47:36 +0000 Subject: [PATCH 028/233] Debian theme --- theme/debian/banner.png | Bin 0 -> 20041 bytes theme/debian/icons/add.png | Bin 0 -> 2138 bytes theme/debian/icons/agpl.png | Bin 0 -> 8393 bytes theme/debian/icons/avatar_news.png | Bin 0 -> 41217 bytes theme/debian/icons/bookmark.png | Bin 0 -> 980 bytes theme/debian/icons/bookmark_inactive.png | Bin 0 -> 978 bytes theme/debian/icons/calendar.png | Bin 0 -> 2404 bytes theme/debian/icons/calendar_notify.png | Bin 0 -> 1367 bytes theme/debian/icons/delete.png | Bin 0 -> 2659 bytes theme/debian/icons/dm.png | Bin 0 -> 2420 bytes theme/debian/icons/download.png | Bin 0 -> 1394 bytes theme/debian/icons/edit.png | Bin 0 -> 2490 bytes theme/debian/icons/edit_notify.png | Bin 0 -> 1444 bytes theme/debian/icons/favicon.ico | Bin 0 -> 1150 bytes theme/debian/icons/like.png | Bin 0 -> 1440 bytes theme/debian/icons/like_inactive.png | Bin 0 -> 1438 bytes theme/debian/icons/links.png | Bin 0 -> 7057 bytes theme/debian/icons/logorss.png | Bin 0 -> 10510 bytes theme/debian/icons/logout.png | Bin 0 -> 7040 bytes theme/debian/icons/mute.png | Bin 0 -> 1026 bytes theme/debian/icons/new.png | Bin 0 -> 1441 bytes theme/debian/icons/newpost.png | Bin 0 -> 2153 bytes theme/debian/icons/newswire.png | Bin 0 -> 6594 bytes theme/debian/icons/pagedown.png | Bin 0 -> 2117 bytes theme/debian/icons/pageup.png | Bin 0 -> 2127 bytes theme/debian/icons/person.png | Bin 0 -> 1418 bytes theme/debian/icons/prev.png | Bin 0 -> 2490 bytes theme/debian/icons/publish.png | Bin 0 -> 6016 bytes theme/debian/icons/qrcode.png | Bin 0 -> 10970 bytes theme/debian/icons/repeat.png | Bin 0 -> 1468 bytes theme/debian/icons/repeat_inactive.png | Bin 0 -> 3667 bytes theme/debian/icons/reply.png | Bin 0 -> 1412 bytes theme/debian/icons/rss3.png | Bin 0 -> 5439 bytes theme/debian/icons/scope_blog.png | Bin 0 -> 992 bytes theme/debian/icons/scope_dm.png | Bin 0 -> 1421 bytes theme/debian/icons/scope_event.png | Bin 0 -> 2404 bytes theme/debian/icons/scope_followers.png | Bin 0 -> 1416 bytes theme/debian/icons/scope_public.png | Bin 0 -> 1446 bytes theme/debian/icons/scope_question.png | Bin 0 -> 2492 bytes theme/debian/icons/scope_reminder.png | Bin 0 -> 4132 bytes theme/debian/icons/scope_report.png | Bin 0 -> 1951 bytes theme/debian/icons/scope_share.png | Bin 0 -> 1612 bytes theme/debian/icons/scope_unlisted.png | Bin 0 -> 1420 bytes theme/debian/icons/search.png | Bin 0 -> 2995 bytes theme/debian/icons/showhide.png | Bin 0 -> 3051 bytes theme/debian/icons/unmute.png | Bin 0 -> 969 bytes theme/debian/icons/vote.png | Bin 0 -> 6308 bytes theme/debian/image.png | Bin 0 -> 111294 bytes theme/debian/left_col_image.png | Bin 0 -> 63242 bytes theme/debian/login_background.jpg | Bin 0 -> 27590 bytes theme/debian/right_col_image.png | Bin 0 -> 21119 bytes theme/debian/search_banner.png | Bin 0 -> 20041 bytes theme/debian/theme.json | 63 +++++++++++++++++++++++ translations/ar.json | 3 +- translations/ca.json | 3 +- translations/cy.json | 3 +- translations/de.json | 3 +- translations/en.json | 3 +- translations/es.json | 3 +- translations/fr.json | 3 +- translations/ga.json | 3 +- translations/hi.json | 3 +- translations/it.json | 3 +- translations/ja.json | 3 +- translations/oc.json | 3 +- translations/pt.json | 3 +- translations/ru.json | 3 +- translations/zh.json | 3 +- 68 files changed, 93 insertions(+), 15 deletions(-) create mode 100644 theme/debian/banner.png create mode 100644 theme/debian/icons/add.png create mode 100644 theme/debian/icons/agpl.png create mode 100644 theme/debian/icons/avatar_news.png create mode 100644 theme/debian/icons/bookmark.png create mode 100644 theme/debian/icons/bookmark_inactive.png create mode 100644 theme/debian/icons/calendar.png create mode 100644 theme/debian/icons/calendar_notify.png create mode 100644 theme/debian/icons/delete.png create mode 100644 theme/debian/icons/dm.png create mode 100644 theme/debian/icons/download.png create mode 100644 theme/debian/icons/edit.png create mode 100644 theme/debian/icons/edit_notify.png create mode 100644 theme/debian/icons/favicon.ico create mode 100644 theme/debian/icons/like.png create mode 100644 theme/debian/icons/like_inactive.png create mode 100644 theme/debian/icons/links.png create mode 100644 theme/debian/icons/logorss.png create mode 100644 theme/debian/icons/logout.png create mode 100644 theme/debian/icons/mute.png create mode 100644 theme/debian/icons/new.png create mode 100644 theme/debian/icons/newpost.png create mode 100644 theme/debian/icons/newswire.png create mode 100644 theme/debian/icons/pagedown.png create mode 100644 theme/debian/icons/pageup.png create mode 100644 theme/debian/icons/person.png create mode 100644 theme/debian/icons/prev.png create mode 100644 theme/debian/icons/publish.png create mode 100644 theme/debian/icons/qrcode.png create mode 100644 theme/debian/icons/repeat.png create mode 100644 theme/debian/icons/repeat_inactive.png create mode 100644 theme/debian/icons/reply.png create mode 100644 theme/debian/icons/rss3.png create mode 100644 theme/debian/icons/scope_blog.png create mode 100644 theme/debian/icons/scope_dm.png create mode 100644 theme/debian/icons/scope_event.png create mode 100644 theme/debian/icons/scope_followers.png create mode 100644 theme/debian/icons/scope_public.png create mode 100644 theme/debian/icons/scope_question.png create mode 100644 theme/debian/icons/scope_reminder.png create mode 100644 theme/debian/icons/scope_report.png create mode 100644 theme/debian/icons/scope_share.png create mode 100644 theme/debian/icons/scope_unlisted.png create mode 100644 theme/debian/icons/search.png create mode 100644 theme/debian/icons/showhide.png create mode 100644 theme/debian/icons/unmute.png create mode 100644 theme/debian/icons/vote.png create mode 100644 theme/debian/image.png create mode 100644 theme/debian/left_col_image.png create mode 100644 theme/debian/login_background.jpg create mode 100644 theme/debian/right_col_image.png create mode 100644 theme/debian/search_banner.png create mode 100644 theme/debian/theme.json diff --git a/theme/debian/banner.png b/theme/debian/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..e294379105a4ffdb50d923e4e36cb18677ca6d93 GIT binary patch literal 20041 zcmX`SWmFt(v^0vlLvVMO;O?%$32uYCyTjlR+%3V~VQ>jHKnNDx-QD5xp7WjiV|vZ% zU)`(su3fdOo@g}{SyUuKBnSuyRCzfmbqEM(iqHRw2vDEbLu4{o2nbjdUrk+ibyF{L zXICeHjlCtgyN|Oaxuv%a00P2$xkg+6#|{t5>j8r+3>3A|$W{|0@95QRs>L+;+`h3Q z#xj-*Hq^umTJw9*TgNQfqgqRLWu{#@z~6RmGcw`e1$!~iwflTAiXp@5cEY>zEod)V{h)$TO*{m9JC=3aen8bRI@zg*mnu*#ha&dIrTdjML?&0509 zCDPv07mz`3Uhc=y4Fr3v0IYU|&lkq0&KDB#jv!R3a6!BflC;o3hU`CcKMLd^Ml;U3 zmvcp-Z((xNZGQg`1pRoL98i18(~@GKHWxrhQodkl3puUD@j_&F0-T~LwC>Kn1OvgfR4JD0_w zDYT93t+U`W?7*=um-JC(zO2jkG~>)@?{IZ6$F^Hu%TK`q@bgAa2qmO1GTp+QAuNlGAoS<{#~bH<{%eud5ae+&vl8qtL-N)A-z8>= za=vA;l2RT|z;FB5zY@Q6J;wf8PUuv(7PT09t~GkB+>?O1_55_-j-Ju0X9fw4l}H5r znj&W`?p?*pa!0pN;#_Fh9it!-veB)UDzrtwBvY>JKP2$Q$G2#e1>!;mI)Rq6IUw}? zz}PnGcm1xbUXBbjj}Le^#JM-{3UBqK+f;mPgCH_`X$ScWPYki_k8aPliv9pBg(P18 zZ-G^tIYCQ}Re!F7U`e=AMA3 z?YLYXm-xPrceV;%GPE}kJoIo!Gn=1r_?-;S43ctaBdcu|gCt^(zdGYsFwG{-X0q^+ z`g=W2#w|vO$ZR84k$BX_D7nDN!a1OG$FPKHYku!Du{tfeUmsfpe8&=DV)t&y6>uVS zVA>^CPv_%OUeSKo53ztta}yku72$sCi@mC} zkzD=<^Hn5fIC!E8;t%_r@LWfT-p+UXDLkZ|TFmlgdN%J#&VvX+0VdI#TYV(4j;F9fQCf183dMEKJV4Y^nr|*a#l&<;*Y2@!mi9Ds2V! zkO?xhru1`L)YG^x#*Fd7M-z$$W&GhVxb+B#lsK9VAy|ySnaUJ13h5UY^pC=wjL~07 zcF=LeH}sNWr;q&~n_g|&fo7}9NWVj-@K)aO;h;cbC4iNUk=8Xn$k*wJp6Ro8UtjV}qG^9s>fPR|Vj0vY?iA0$L}F8=3Dcz1ba zY4}}a0#s`HMQI382nccrc`0#C@8#2OnKR}#9u=Onpdl)GSAv6ZQ z34|FO5gs!&1*U<>pIc=BrRW%S%FM0eV>IAv)-BO3w#C=1Xj)*gTy``Lh065bS;Lj8 zwmmG&hfYD!RUmk@O>^9H}Oa;!A((suxnJQxxhg)<701R4cHwnWlWQY6Z?I=p=h6^*Jr;Gp+a z*8AeTk@9r0YW8NyUglh36lLdnP6ZBX^=qn-xEU3pv%&~;N8lNa@mI}=cRpi z@4+VUZn|XT@2|7dpenp+qsB7F#Fu?f(%$MNZ*+U!Ohm`MZ_Z{>@8Ab5#~10t9As$yYNs ztx5iaT&;QVY96u9h4UW|y2S|LKfQ)YiJmiQBWC^x^6|h=KzD|R956xCvgGm|J-<&~ zWRZ=TkEZvk0X@hTR0IKEoCUtFzTkP1lAWG)d<*31ygm&$Ps|tO#Ky$D^UFjC2L7DG ziU#hkLgJWP0(Nc=EHO%}*258vTO<74C$k?H>^$uupd!tSElsKWAe#iHzB{0_@~((F zO?{On1}E!0o*A!!ysQ{j#h19wC#59L|27L6U+bzB8Sl{p`%tRjraZo=s7^18sG^kPEUVXKBvVi4k6!6%Y@T}T+C_E{F zT{OVoLiw%kMA)1J!~3;-87ntVYbu9rqpq1`9A($^c}A3xh=59_hNmp z>v~D#U$PQ+hu^;>9y0I2@B<;-uauM>iUU`UnJuzqPlJg`T<04K6JKte*)BYoHr}lJ zw_qUo`8zaJ1L5=4kFC$YC{F2tEcmIIG)>Vsk>+JI`X|x`9b;m3E3nXza5;#C_m;oX z8>6{Vxp9UOgd0~4Isk}pbz8qnN$p-<)~hi=R4PaX1A&z)#CD&(IX%)$n|;?&!fX6R z7T00#iyIw~0~0bm^MR}8>V&N8B@Z3<%Yu>?O}_rzmmi%e9eCI%f~8^4LeysDx@e?m zko;XXLHqYBRf(keuTf+Wkd#NSLd3+@IV0%q7a2zB2%NlOSQ zGG%r!cFrN2fH6W~+Kh&d&lI3tiij$|5E?4?j(nesL?sX#a75y)mjg1J!MG7EPUW`# z#I_v(g8`)xBH3Y2cc5oI4#TXhEGUzGeDk=g*H@tfX7vm#x~5g~**w05Pr#YXz9b+G zz54DXyh16fD6p|&T(h|BDWNsa0=SLuz3SdC6u6;=ztP6d=0-#F*4Cfp?;lr?H`(xR zrxQQXL+|qzZ7|2RqC+RG3B1){Ua4FUE99KWMs6#tF`)`h4qIKzC4r%&+&8MDbn{|^ zVLGVhf9Q&Vi_)%O#p?GXYIoXYB3ueSz2Q&luIL5of-yXKGj|As{4S&O8VvHG3>Muu-KNhqrRt*1l|QkwSkJgTPgQN?_cVC93PHiS2u(X1%{-2f zr1vA|_Qt88RBHsybr%Mgi{+Rf%<5On`vV+qC4jMd!Q=v@pcZ_aKyNra?hfKq)zPZ2soeKM1Qpvu9;hFLA zeo@@Aic!;NY1C07eU>W&2Vkc{2+tEEXE*lx&cO*LaRj`rxL+QaF9i`QOtw8XD1;S( z%2HjY#OOr=FvphG()d?XQ@Q`AFS7sZ3$JnR>iO1f`|JS6HLo`7;keh&K^eF+?*A$zObLN6^hk&I}$E zl^!G#^vXyoN|Gt$9Vt{XNns|ZYLm+?6%NT*^aJc_Ou;~1{GaKu0(+8c@!~37icY6r z*?i@{9e3o9AUcOhB_xNFICIjOVS>gBhR`T@c(v}{(V(#dCZ`6>8op`-OZ}wg!|6U= zsL`*QXFMpaeSq9u)zq4ATVy;4M>&n6J~rLr->#UXnpavWGsl5Z8fu2 z2!Tv&(;&eusZE=IzlTg|S;1&ocmn>WxT)0?=pR!c5{?Z_shXQn+>0G{%ij<&5arKW z>shM>xn726iDkPv5-B5=)}we~P}z}%@o454OhTCc-t=cAt)>*rzGEpa$XZ#G^|e}( zA?xi#2<7WnOp@vtEG4N+qIY|sz>XcA6xuV=r(xW0{IL+Z^%QmUp%=UKD->x}cdWs? z2KWe-;qh>D;|3wsaMF1_sEo-R*X4*!tK_|7z0iy;0&lN$LDT?g($^xKc_9vEy9pu# z2R5%kKQ_wCm8tV-iS?L;$_(6*M*=CgjB?L8c|Y#Fl}uu`Aj zJ25VHYNWzn1xGToNuUfFq>`qJLhx8jbYIq7JJXIcWHEv_HPW7ulmtGz+=**4d#-xg zzwE(ZE<|WmtWRXyx25k)cs17Rec?f*vNPtsOFjZ2_D<221B>5e4rD|Ny>QcSumY1A z&InK)Iq-Flv7AV@!RDU=OQm6AZi_1|*Gx}Irr>A zcoEQ5;vJhG#zq&+FtmY8SNI~uIVdq>pfGV=C^wYpS?O$fILZf--$|WM|-!dKlC~kbX6eyl+__qC#h`6YMOA05ln)nn^hp` z4E4gJ?RGP3>2q={8Dz8f>xB1_!9m-7tvG=x{ocyErfd?*_xb)0jf&frCzS45lQuIa zkhH){^cjC77XQE+TM(#chJopVgw)n-koT7OG5c}p^*&W_Hs93kdw)3Q;`m)oto3~q zRm9Vb{U541_M9B*@;(R79S~`zgSPs{cmIw{#q-H)cxieuV%AYH983|8uOL{I7+UuX zy3_V&yZ!>9(NaB16e`U%RN_QCZ_uJA(izSAp6&l~aorTu5V0gblFhy~X>?A1lCXw$hcIvAtpCbq5TEnYToK@p1P-37mQ2Zrvjl$Njh`cx9-hw2h)0VDHe z9F4`a)xnu8`qd#0;$3wshWO85D-A8`dDbeAjn|fk3t}){q38!Fs1?uZV>0M%qgJ$s z>>ll!{kGm2DKw{&AF|67mg^aAw#@kN;e;}o@$>k%W%Z+N_}(G+FQ)Mn1LC?;%3j;l zt-B+T>`lQ4YFdf}{24sK>lIo6Di!I${{`ZKgT4l0NM~|Xp)ph#3yD@ZAJh=c#Px^I2YUz#zv3&6V51C2n32Hp2v5z;&@p(@+f(j9Vn zH|_b{A|&q2usfaJw|?Ii6Ut21=~+6_S9apl14}BbJU=(A!CL%bVI;G5<};ig>AH1c zS?II%xoj``UOx)mue%+BX~Z!hjHpe>YkA^D-oLf9S}yX4kDMK`L7h_0Wrm-un=Zip}KS? zS_7dK#HzjP*DcKa+^7~(`Y4ME2fSEmknZsl)&%zgNn;3t#K!wQJV)eUH~-+rwJNSP^kel{OJcSB84-`6ch2yW;nK|kGqaTfL?y7;GBx>C|z|z%nt=YTY;hM;-iibFsM*tT> z0*)P8#QUOK^r;(u?zA_6w}5rFlmBtNyVUT`ZG$)*bL2P!^zOL~)YV~GDySo~v%@K| z;*2r87%857k#>45Qhc>J@mW@~gtJI`4&Cab4)C`q5K5LgS;%f0zP<%_hHtO&L}8l_ z2EMYr?-{=y4x$I$hLMp?p?}=bMMl- zuJz9EuQ0K7^VDFm<4AZ{EKnp`2gHz4AWYB7j>Kqnd>Ei!GprH%0+~Lq9!V(1+&EwB zKb!MUHMIxO#QN0mOsfR7G_}@?6UYqJBW#F4_X)!M3l?L({2mtW@@pu8tZggx_jvI0 z`6>NhW5Fk$K9PFy-N4MA_l-B5#0MK;bMwkC7VAmo7wlo{xK_+#+oK!?s-i!mEBg82}RAd#8X=?oc|8w^VT> z_+BD%YP5|ddv0`Yu4kBrnw&YmC1S_&arwSYhkiXsRX&Jl2!%Oqt3mRphJMlkblgbQ zusQnKP|KM*Uk)BNjdWARW0k(TP?wM5%v`Fl5J~+8mo|%uWFmCJX$)~=pWGSsWAM0sS1l3YeMu*JMxr0E#)No!pakNZT{atoC-?sCI zkeJ7owcM@`t*NFZcDC4}RV5fBEGGVQIxxHl8f$MH#FdmX|2vEsi>B^j{oW0yI#?`F6*oy84EK?i%i5Ge$ zuXBX2STUI)ZX?(NRR4#JYj|zNhW+j~4gbpsKqH9NPf%9ugfi8x%i#<*L_qO>TYCt4 zSuB9bFcm(PAIvBgJ-N2=kdFUb_wF-+g)qM^^y{Z#nd2LmFfNO!j+FFJj0tTLD3gSk z^k1W%u#m8bz|1gG6`a)ppGXvk!eD7u)`IE~h0uK&`%hL`yusW`lpA)3{C`B~|*}wxsS@ zh=9lZpqb3`^gpqm`8fc7>FK+KJu4|}+%2VwJCn;*Pvy*uOi$MgGY^2gJ`Nu;xM?6U zhgR2aeuGquAB82UXced;w)N=4-aIi)hC78l)Qck9$7;1b7?Hxgvcxz{lZ7A{;@zYXUcQvH%kqU z)94H*L)9FwfH3t18BR_zzz(~lu2~_4wR@D>{b}Wa@Gg!11WQ#0`$G)^{6mgoBmNy{ zAfiH ze&_ZZa&IisRejCI38gfF8v_wKAz`l{7hB%4_Ip5A+rH9^Ip1CDcuCH$`{JTAcVrq)3ZMsi>v)A>)i!lNdgFPnB_*r-Eh z!H$xY5c|b7m%44T`_+qhv(;q1Kxxr;j$vtg8&P z8}P972VrD(iSZu<#q2KS|ELr;ZC3}^Np_H+3Du1tv@?CbGDEoizT9ILsQ1;c_swZG zn(P!LfVbmzb@eBMI=pC9CxYf5kn5S-tEXL6k*&x)(D~3% zCZZ8zGipt*;f5b!-H{R!rTLd*rekUBkIXN%BTFud%swS?K47KqSpR^^tTm$DA8{pD zFV2&a`qs6SjCf1lqBcX{i}zu+jQ?#YY@>AZs|es-k=eh*pF|%qOCZ2Kr?CyL?8YM~ z==#rst6iN7tVyuFc7x70;FA!-f}_G-nF}+@@y4ObDFU3Re$$hXzH@E7!#uID|IY#; z-MY@ddGHD4j26-eCEUr*<*KHNih(sHNOnw}`7aY4qVscaHl_BI zP-97AYSsG-UM$%U;lAFKbT|!mU}MK)4C@MY&Je0Jaq)AhpM$igx93^OlE5_*faCs- z&-4zy*7DJ%w<)Y$m*|K%-utghs{a-2*hZ*Ngp84bb`gy0JuA6Fe6J}R84u@qS{5P6 zf=PVea4*%`e3qd;B8v5VxwAUUbq#--plR1r0bnG-c|Dlk?Y3JqC3qD_UgrYSdY z9-rH1u5}?z91R4Ny5f@7m+KF;lpj6Y!=x)m#UZG*Fd6)vtm;cZIoRLGd3aeY=Imc# z&0gty`|Tsx6sflUA3UUmN!GI>Dk2n}2tZJ7FAtC;U#+jLY&;F$)!51#D##ya0bs=u z_f6mhaUQV_b%%Bx|MY(|`tfHXTR2?*FHdUB=+L}wUUYG?MH6k&gleEK*$M6h97Bna z+?VulsxSy1H$Vcl+BE;XR*R6};yjX6Ia4NJq8!G@>5Z^q=Gs!q1Z}Ub(8aW3pLdbrU2g0+N?hQy`cm!-*O9dc zmK2PLXVFbGC)d}rlWdx zRiV%PpA|(Z%HND+gj!s41Ju!?Y!78SIgjp*Jru-tx8T{4jn|Qn$6ZgMnKW%zyAP9Z zLFkNDA? zN+u3nH;lzF=-5i2DyDJi+~};tGC>|ChN1BY@WL99j*3l@L5}=?IEj%-ZJixuPH~FC zmAaGTP7!=%t(cdM!D#PpnjN7D{o$PB&sYxZBSLIazss?>e@ceDx^0x zres^3oH-hdLciKY%*JIdw>{nXUCeNe776LQe8Cikz%Mtda8nRQQniP~P(*FpIjGQm z8YBG{I{40j0w`O&c=p4>x>9m#@IrkfAcYWy?ki&vU#{5}> zfq&dkJtaC^w$^zy$d#*W3OU}Ko7mu}wwOs$tS8U2xQ?qC6RfR{9tp`7Mw34=nlS(e%p?J%gV2<9 z_NBf;Fr^8y4UfN`hVL_)zw=ma5vE0qW+6x&qj6%~eaCPM;!`XP}Tm9-TtzZ2>BQTY9qhjtYMZxxq5YOVp9_+)~sDDe7o z8FyJ~{?)vjdh&V#1{r}l-czjR4C%!WSe!_vx$!d9ZTz+$^>ljvPJF`2Ra3#>f>UbW zNRX=3E*`Pt1_M2@GmDTg6hecAi~y(J`#~l;WEQUl?It($io1+LDz?IpNhI_Q3FbO48d$!&Y5e_CIg^Z-B zuOmzn&aqXUHCMc!C`C@Rq%*GkBxSHj_nL|`hYsY^`vLs}?KpNc#Vn z%tQ@A#=?%srhLu5-U=%u*lF#10g1VG(7{9Cfo$$W;Qd)tBH6HSy2+^CWJh-NL&@9M z!6#&6npFfWx9BuC2)&HO1FH$T5${L*ve^E?TD34sO0*$jz>?wE%P0f{xTq4!Wzl2U z309UMPx<(C3Jss5Z^?CK$u*u88ob{;CT#+xL1AqF-Sl(#V0Zt#lGn3vq(y=ffc7aMm%ttF0JSFtHP33NX9%8^Tuyb?en%ot59#2A ziGI()ZMFh-?9Zix=>WBva=Z2=eU>hPPu;Rp4h}l{0{Xc*tLVqWhrLUik#?)S4z-e0 zlkI}-eQuM@*dpshT;ev+cjbjM*4F%37WA`-d5GxPB%={xoCR;8W4otptH$Rk>MoI` z(=hqmdWYd63xyH3&ef}vkKZ?RR-=05Ya=Fnn@cAI{0|IZIZhc^Q`wLrjyzP2ntpoO z2e3c+=gTeRsbl5oP~qm!%4K(J!Ou{IO-8##r3QhuWRIZT#jJGuf$;@$UMMHb(5|I| z<%&fy29%{G{(*fdj8)Q)CMWDUVZ(q1yYwItEe`>w?cazcj%e$M3iN&T1Mi+?;anzQGko%=s zVrek0#�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%0DXqt}i=c;( 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 literal 0 HcmV?d00001 diff --git a/theme/debian/icons/add.png b/theme/debian/icons/add.png new file mode 100644 index 0000000000000000000000000000000000000000..02a632a519734275b2b724d82f7d6249bb71c1d6 GIT binary patch literal 2138 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 literal 0 HcmV?d00001 diff --git a/theme/debian/icons/avatar_news.png b/theme/debian/icons/avatar_news.png new file mode 100644 index 0000000000000000000000000000000000000000..0196a526e936fdae7843209e543265eb43328fd5 GIT binary patch literal 41217 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%0A^Ws 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