diff --git a/blocking.py b/blocking.py index fed8af9a5..836f85ca2 100644 --- a/blocking.py +++ b/blocking.py @@ -67,7 +67,7 @@ def removeGlobalBlock(baseDir: str, if os.path.isfile(unblockingFilename): if unblockHandle in open(unblockingFilename).read(): with open(unblockingFilename, 'r') as fp: - with open(unblockingFilename + '.new', 'w') as fpnew: + with open(unblockingFilename + '.new', 'w+') as fpnew: for line in fp: handle = line.replace('\n', '').replace('\r', '') if unblockHandle not in line: @@ -80,7 +80,7 @@ def removeGlobalBlock(baseDir: str, if os.path.isfile(unblockingFilename): if unblockHashtag + '\n' in open(unblockingFilename).read(): with open(unblockingFilename, 'r') as fp: - with open(unblockingFilename + '.new', 'w') as fpnew: + with open(unblockingFilename + '.new', 'w+') as fpnew: for line in fp: blockLine = \ line.replace('\n', '').replace('\r', '') @@ -104,7 +104,7 @@ def removeBlock(baseDir: str, nickname: str, domain: str, if os.path.isfile(unblockingFilename): if unblockHandle in open(unblockingFilename).read(): with open(unblockingFilename, 'r') as fp: - with open(unblockingFilename + '.new', 'w') as fpnew: + with open(unblockingFilename + '.new', 'w+') as fpnew: for line in fp: handle = line.replace('\n', '').replace('\r', '') if unblockHandle not in line: diff --git a/bookmarks.py b/bookmarks.py index 0039a6d89..22387d395 100644 --- a/bookmarks.py +++ b/bookmarks.py @@ -57,7 +57,7 @@ def undoBookmarksCollectionEntry(recentPostsCache: {}, indexStr = '' with open(bookmarksIndexFilename, 'r') as indexFile: indexStr = indexFile.read().replace(bookmarkIndex + '\n', '') - bookmarksIndexFile = open(bookmarksIndexFilename, 'w') + bookmarksIndexFile = open(bookmarksIndexFilename, 'w+') if bookmarksIndexFile: bookmarksIndexFile.write(indexStr) bookmarksIndexFile.close() @@ -213,7 +213,7 @@ def updateBookmarksCollection(recentPostsCache: {}, print('WARN: Failed to write entry to bookmarks index ' + bookmarksIndexFilename + ' ' + str(e)) else: - bookmarksIndexFile = open(bookmarksIndexFilename, 'w') + bookmarksIndexFile = open(bookmarksIndexFilename, 'w+') if bookmarksIndexFile: bookmarksIndexFile.write(bookmarkIndex + '\n') bookmarksIndexFile.close() diff --git a/daemon.py b/daemon.py index 15ecc1c5a..6795a1504 100644 --- a/daemon.py +++ b/daemon.py @@ -292,7 +292,7 @@ class PubServer(BaseHTTPRequestHandler): if not minimal and minimalFileExists: os.remove(minimalFilename) elif minimal and not minimalFileExists: - with open(minimalFilename, 'w') as fp: + with open(minimalFilename, 'w+') as fp: fp.write('\n') def _sendReplyToQuestion(self, nickname: str, messageId: str, @@ -539,7 +539,7 @@ class PubServer(BaseHTTPRequestHandler): if not etag: etag = sha1(data).hexdigest() # nosec try: - with open(mediaFilename + '.etag', 'w') as etagFile: + with open(mediaFilename + '.etag', 'w+') as etagFile: etagFile.write(etag) except BaseException: pass @@ -5108,7 +5108,7 @@ class PubServer(BaseHTTPRequestHandler): mediaBinary = avFile.read() etag = sha1(mediaBinary).hexdigest() # nosec try: - with open(mediaTagFilename, 'w') as etagFile: + with open(mediaTagFilename, 'w+') as etagFile: etagFile.write(etag) except BaseException: pass @@ -5255,7 +5255,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.baseDir + '/accounts/' + \ nickname + '@' + self.server.domain + '/.lastUsed' try: - lastUsedFile = open(lastUsedFilename, 'w') + lastUsedFile = open(lastUsedFilename, 'w+') if lastUsedFile: lastUsedFile.write(str(int(time.time()))) lastUsedFile.close() @@ -5842,7 +5842,9 @@ class PubServer(BaseHTTPRequestHandler): self.server.httpPrefix, self.server.domain, self.server.port, - loginNickname, loginPassword): + loginNickname, + loginPassword, + self.server.manualFollowerApproval): self.server.POSTbusy = False if callingDomain.endswith('.onion') and \ self.server.onionDomain: @@ -5901,7 +5903,7 @@ class PubServer(BaseHTTPRequestHandler): loginNickname + ' ' + str(e)) else: try: - with open(saltFilename, 'w') as fp: + with open(saltFilename, 'w+') as fp: fp.write(salt) except Exception as e: print('WARN: Unable to save salt for ' + @@ -5915,7 +5917,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.baseDir+'/accounts/' + \ loginHandle + '/.token' try: - with open(tokenFilename, 'w') as fp: + with open(tokenFilename, 'w+') as fp: fp.write(token) except Exception as e: print('WARN: Unable to save token for ' + @@ -8324,7 +8326,8 @@ def runDaemon(blogsInstance: bool, mediaInstance: bool, domainMaxPostsPerDay=8640, accountMaxPostsPerDay=864, allowDeletion=False, debug=False, unitTest=False, instanceOnlySkillsSearch=False, sendThreads=[], - useBlurHash=False) -> None: + useBlurHash=False, + manualFollowerApproval=True) -> None: if len(domain) == 0: domain = 'localhost' if '.' not in domain: @@ -8356,6 +8359,7 @@ def runDaemon(blogsInstance: bool, mediaInstance: bool, httpd.blocklistUpdateInterval = 100 httpd.domainBlocklist = getDomainBlocklist(baseDir) + httpd.manualFollowerApproval = manualFollowerApproval httpd.onionDomain = onionDomain httpd.i2pDomain = i2pDomain httpd.useBlurHash = useBlurHash diff --git a/epicyon-blog.css b/epicyon-blog.css index 6d289bdaa..a2ceee5d8 100644 --- a/epicyon-blog.css +++ b/epicyon-blog.css @@ -48,7 +48,7 @@ font-family: 'Bedstead'; font-style: normal; font-weight: normal; - font-display: swap; + font-display: block; src: url('./fonts/bedstead.otf') format('opentype'); } diff --git a/epicyon-calendar.css b/epicyon-calendar.css index 4a1148133..cbf3471d3 100644 --- a/epicyon-calendar.css +++ b/epicyon-calendar.css @@ -19,7 +19,7 @@ font-family: 'Bedstead'; font-style: normal; font-weight: normal; - font-display: swap; + font-display: block; src: url('./fonts/bedstead.otf') format('opentype'); } diff --git a/epicyon-follow.css b/epicyon-follow.css index 6981ea92a..a9f8a5333 100644 --- a/epicyon-follow.css +++ b/epicyon-follow.css @@ -36,7 +36,7 @@ font-family: 'Bedstead'; font-style: normal; font-weight: normal; - font-display: swap; + font-display: block; src: url('./fonts/bedstead.otf') format('opentype'); } diff --git a/epicyon-login.css b/epicyon-login.css index c0279dc8b..bda7b678a 100644 --- a/epicyon-login.css +++ b/epicyon-login.css @@ -25,7 +25,7 @@ font-family: 'Bedstead'; font-style: normal; font-weight: normal; - font-display: swap; + font-display: block; src: url('./fonts/bedstead.otf') format('opentype'); } diff --git a/epicyon-profile.css b/epicyon-profile.css index 247b8449e..ef1796cc0 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -56,7 +56,7 @@ font-family: 'Bedstead'; font-style: normal; font-weight: normal; - font-display: swap; + font-display: block; src: url('./fonts/bedstead.otf') format('opentype'); } diff --git a/epicyon-suspended.css b/epicyon-suspended.css index 550fa7c87..7ace9ba3f 100644 --- a/epicyon-suspended.css +++ b/epicyon-suspended.css @@ -25,7 +25,7 @@ font-family: 'Bedstead'; font-style: normal; font-weight: normal; - font-display: swap; + font-display: block; src: url('./fonts/bedstead.otf') format('opentype'); } diff --git a/epicyon.py b/epicyon.py index 791c1e1cf..a6a8bd900 100644 --- a/epicyon.py +++ b/epicyon.py @@ -163,6 +163,9 @@ parser.add_argument('--json', dest='json', type=str, default=None, help='Show the json for a given activitypub url') parser.add_argument('-f', '--federate', nargs='+', dest='federationList', help='Specify federation list separated by spaces') +parser.add_argument("--noapproval", type=str2bool, nargs='?', + const=True, default=False, + help="Allow followers without approval") parser.add_argument("--mediainstance", type=str2bool, nargs='?', const=True, default=False, help="Media Instance - favor media over text") @@ -476,7 +479,7 @@ if args.socnet: httpPrefix, debug, __version__) try: - with open('socnet.dot', 'w') as fp: + with open('socnet.dot', 'w+') as fp: fp.write(dotGraph) print('Saved to socnet.dot') except BaseException: @@ -1265,7 +1268,7 @@ if args.addaccount: print('Account is deactivated') sys.exit() createPerson(baseDir, nickname, domain, port, httpPrefix, - True, args.password.strip()) + True, not args.noapproval, args.password.strip()) if os.path.isdir(baseDir + '/accounts/' + nickname + '@' + domain): print('Account created for ' + nickname + '@' + domain) else: @@ -1696,16 +1699,16 @@ if args.testdata: str(maxRegistrations)) createPerson(baseDir, 'maxboardroom', domain, port, httpPrefix, - True, password) + True, False, password) createPerson(baseDir, 'ultrapancake', domain, port, httpPrefix, - True, password) + True, False, password) createPerson(baseDir, 'drokk', domain, port, httpPrefix, - True, password) + True, False, password) createPerson(baseDir, 'sausagedog', domain, port, httpPrefix, - True, password) + True, False, password) createPerson(baseDir, nickname, domain, port, httpPrefix, - True, 'likewhateveryouwantscoob') + True, False, 'likewhateveryouwantscoob') setSkillLevel(baseDir, nickname, domain, 'testing', 60) setSkillLevel(baseDir, nickname, domain, 'typing', 50) setRole(baseDir, nickname, domain, 'instance', 'admin') @@ -1807,4 +1810,4 @@ runDaemon(args.blogsinstance, args.mediainstance, args.accountMaxPostsPerDay, args.allowdeletion, debug, False, args.instanceOnlySkillsSearch, [], - args.blurhash) + args.blurhash, not args.noapproval) diff --git a/filters.py b/filters.py index 81335234b..744e28775 100644 --- a/filters.py +++ b/filters.py @@ -32,7 +32,7 @@ def removeFilter(baseDir: str, nickname: str, domain: str, if os.path.isfile(filtersFilename): if words in open(filtersFilename).read(): with open(filtersFilename, 'r') as fp: - with open(filtersFilename + '.new', 'w') as fpnew: + with open(filtersFilename + '.new', 'w+') as fpnew: for line in fp: line = line.replace('\n', '') if line != words: diff --git a/followingCalendar.py b/followingCalendar.py index f414634b7..10c5ae39e 100644 --- a/followingCalendar.py +++ b/followingCalendar.py @@ -29,7 +29,7 @@ def receivingCalendarEvents(baseDir: str, nickname: str, domain: str, # create a new calendar file from the following file with open(followingFilename, 'r') as followingFile: followingHandles = followingFile.read() - with open(calendarFilename, 'w') as fp: + with open(calendarFilename, 'w+') as fp: fp.write(followingHandles) return handle + '\n' in open(calendarFilename).read() @@ -65,7 +65,7 @@ def receiveCalendarEvents(baseDir: str, nickname: str, domain: str, # create a new calendar file from the following file with open(followingFilename, 'r') as followingFile: followingHandles = followingFile.read() - with open(calendarFilename, 'w') as fp: + with open(calendarFilename, 'w+') as fp: fp.write(followingHandles) # already in the calendar file? @@ -75,14 +75,14 @@ def receiveCalendarEvents(baseDir: str, nickname: str, domain: str, return # remove from calendar file followingHandles = followingHandles.replace(handle + '\n', '') - with open(calendarFilename, 'w') as fp: + with open(calendarFilename, 'w+') as fp: fp.write(followingHandles) else: # not already in the calendar file if add: # append to the list of handles followingHandles += handle + '\n' - with open(calendarFilename, 'w') as fp: + with open(calendarFilename, 'w+') as fp: fp.write(followingHandles) diff --git a/fonts/bgrove.woff b/fonts/bgrove.woff new file mode 100644 index 000000000..0953886ad Binary files /dev/null and b/fonts/bgrove.woff differ diff --git a/inbox.py b/inbox.py index c8545e49a..864def14e 100644 --- a/inbox.py +++ b/inbox.py @@ -1702,7 +1702,7 @@ def dmNotify(baseDir: str, handle: str, url: str) -> None: return dmFile = accountDir + '/.newDM' if not os.path.isfile(dmFile): - with open(dmFile, 'w') as fp: + with open(dmFile, 'w+') as fp: fp.write(url) @@ -1744,14 +1744,24 @@ def likeNotify(baseDir: str, domain: str, onionDomain: str, # was there a previous like notification? if os.path.isfile(prevLikeFile): # is it the same as the current notification ? - with open(prevLikeFile, 'r') as likeFile: - prevLikeStr = likeFile.read() + with open(prevLikeFile, 'r') as fp: + prevLikeStr = fp.read() if prevLikeStr == likeStr: return - with open(prevLikeFile, 'w') as fp: - fp.write(likeStr) - with open(likeFile, 'w') as fp: - fp.write(likeStr) + try: + with open(prevLikeFile, 'w+') as fp: + fp.write(likeStr) + except BaseException: + print('ERROR: unable to save previous like notification ' + + prevLikeFile) + pass + try: + with open(likeFile, 'w+') as fp: + fp.write(likeStr) + except BaseException: + print('ERROR: unable to write like notification file ' + + likeFile) + pass def replyNotify(baseDir: str, handle: str, url: str) -> None: @@ -1762,7 +1772,7 @@ def replyNotify(baseDir: str, handle: str, url: str) -> None: return replyFile = accountDir + '/.newReply' if not os.path.isfile(replyFile): - with open(replyFile, 'w') as fp: + with open(replyFile, 'w+') as fp: fp.write(url) @@ -1777,7 +1787,7 @@ def gitPatchNotify(baseDir: str, handle: str, patchFile = accountDir + '/.newPatch' subject = subject.replace('[PATCH]', '').strip() handle = '@' + fromNickname + '@' + fromDomain - with open(patchFile, 'w') as fp: + with open(patchFile, 'w+') as fp: fp.write('git ' + handle + ' ' + subject) @@ -1949,7 +1959,7 @@ def inboxUpdateCalendar(baseDir: str, handle: str, postJsonObject: {}) -> None: calendarNotificationFilename = \ baseDir + '/accounts/' + handle + '/.newCalendar' calendarNotificationFile = \ - open(calendarNotificationFilename, 'w') + open(calendarNotificationFilename, 'w+') if calendarNotificationFile: calendarNotificationFile.write('/calendar?year=' + str(eventYear) + diff --git a/media.py b/media.py index 4afa96571..7c6b87306 100644 --- a/media.py +++ b/media.py @@ -122,7 +122,7 @@ def updateEtag(mediaFilename: str) -> None: etag = sha1(data).hexdigest() # nosec # save the hash try: - with open(mediaFilename + '.etag', 'w') as etagFile: + with open(mediaFilename + '.etag', 'w+') as etagFile: etagFile.write(etag) except BaseException: pass diff --git a/migrate.py b/migrate.py index ac9502e03..6fb8bee28 100644 --- a/migrate.py +++ b/migrate.py @@ -25,7 +25,7 @@ def migrateFollows(followFilename: str, oldHandle: str, newFollowData = followData.replace(oldHandle, newHandle) if followData == newFollowData: return - with open(followFilename, 'w') as followFile: + with open(followFilename, 'w+') as followFile: followFile.write(newFollowData) diff --git a/person.py b/person.py index 2196b68b3..78b20a01e 100644 --- a/person.py +++ b/person.py @@ -165,6 +165,7 @@ def randomizeActorImages(personJson: {}) -> None: def createPersonBase(baseDir: str, nickname: str, domain: str, port: int, httpPrefix: str, saveToFile: bool, + manualFollowerApproval: bool, password=None) -> (str, str, {}, {}): """Returns the private key, public key, actor and webfinger endpoint """ @@ -184,7 +185,8 @@ def createPersonBase(baseDir: str, nickname: str, domain: str, port: int, domain = domain + ':' + str(port) personType = 'Person' - approveFollowers = False + # Enable follower approval by default + approveFollowers = manualFollowerApproval personName = nickname personId = httpPrefix + '://' + domain + '/users/' + nickname inboxStr = personId + '/inbox' @@ -351,7 +353,8 @@ def createPersonBase(baseDir: str, nickname: str, domain: str, port: int, def registerAccount(baseDir: str, httpPrefix: str, domain: str, port: int, - nickname: str, password: str) -> bool: + nickname: str, password: str, + manualFollowerApproval: bool) -> bool: """Registers a new account from the web interface """ if accountExists(baseDir, nickname, domain): @@ -366,6 +369,7 @@ def registerAccount(baseDir: str, httpPrefix: str, domain: str, port: int, newPerson, webfingerEndpoint) = createPerson(baseDir, nickname, domain, port, httpPrefix, True, + manualFollowerApproval, password) if privateKeyPem: return True @@ -381,7 +385,7 @@ def createGroup(baseDir: str, nickname: str, domain: str, port: int, newPerson, webfingerEndpoint) = createPerson(baseDir, nickname, domain, port, httpPrefix, saveToFile, - password) + False, password) newPerson['type'] = 'Group' return privateKeyPem, publicKeyPem, newPerson, webfingerEndpoint @@ -406,6 +410,7 @@ def savePersonQrcode(baseDir: str, def createPerson(baseDir: str, nickname: str, domain: str, port: int, httpPrefix: str, saveToFile: bool, + manualFollowerApproval: bool, password=None) -> (str, str, {}, {}): """Returns the private key, public key, actor and webfinger endpoint """ @@ -424,7 +429,9 @@ def createPerson(baseDir: str, nickname: str, domain: str, port: int, newPerson, webfingerEndpoint) = createPersonBase(baseDir, nickname, domain, port, httpPrefix, - saveToFile, password) + saveToFile, + manualFollowerApproval, + password) if noOfAccounts(baseDir) == 1: # print(nickname+' becomes the instance admin and a moderator') setRole(baseDir, nickname, domain, 'instance', 'admin') @@ -432,6 +439,12 @@ def createPerson(baseDir: str, nickname: str, domain: str, port: int, setRole(baseDir, nickname, domain, 'instance', 'delegator') setConfigParam(baseDir, 'admin', nickname) + if manualFollowerApproval: + followDMsFilename = baseDir + '/accounts/' + \ + nickname + '@' + domain + '/.followDMs' + with open(followDMsFilename, "w") as fFile: + fFile.write('\n') + if not os.path.isdir(baseDir + '/accounts'): os.mkdir(baseDir + '/accounts') if not os.path.isdir(baseDir + '/accounts/' + nickname + '@' + domain): @@ -469,7 +482,7 @@ def createSharedInbox(baseDir: str, nickname: str, domain: str, port: int, """Generates the shared inbox """ return createPersonBase(baseDir, nickname, domain, port, httpPrefix, - True, None) + True, True, None) def createCapabilitiesInbox(baseDir: str, nickname: str, @@ -478,7 +491,7 @@ def createCapabilitiesInbox(baseDir: str, nickname: str, """Generates the capabilities inbox to sign requests """ return createPersonBase(baseDir, nickname, domain, port, - httpPrefix, True, None) + httpPrefix, True, True, None) def personUpgradeActor(baseDir: str, personJson: {}, @@ -991,7 +1004,7 @@ def isPersonSnoozed(baseDir: str, nickname: str, domain: str, with open(snoozedFilename, 'r') as snoozedFile: content = snoozedFile.read().replace(replaceStr, '') if content: - writeSnoozedFile = open(snoozedFilename, 'w') + writeSnoozedFile = open(snoozedFilename, 'w+') if writeSnoozedFile: writeSnoozedFile.write(content) writeSnoozedFile.close() @@ -1044,7 +1057,7 @@ def personUnsnooze(baseDir: str, nickname: str, domain: str, with open(snoozedFilename, 'r') as snoozedFile: content = snoozedFile.read().replace(replaceStr, '') if content: - writeSnoozedFile = open(snoozedFilename, 'w') + writeSnoozedFile = open(snoozedFilename, 'w+') if writeSnoozedFile: writeSnoozedFile.write(content) writeSnoozedFile.close() diff --git a/petnames.py b/petnames.py index e28048250..7046a5d94 100644 --- a/petnames.py +++ b/petnames.py @@ -40,7 +40,7 @@ def setPetName(baseDir: str, nickname: str, domain: str, else: newPetnamesStr += entry # save the updated petnames file - with open(petnamesFilename, 'w') as petnamesFile: + with open(petnamesFilename, 'w+') as petnamesFile: petnamesFile.write(newPetnamesStr) return True # entry does not exist in the petnames file @@ -49,7 +49,7 @@ def setPetName(baseDir: str, nickname: str, domain: str, return True # first entry - with open(petnamesFilename, 'w') as petnamesFile: + with open(petnamesFilename, 'w+') as petnamesFile: petnamesFile.write(entry) return True diff --git a/posts.py b/posts.py index dfcfc100f..fdca227b5 100644 --- a/posts.py +++ b/posts.py @@ -599,7 +599,7 @@ def addSchedulePost(baseDir: str, nickname: str, domain: str, print('WARN: Failed to write entry to scheduled posts index ' + scheduleIndexFilename + ' ' + str(e)) else: - scheduleFile = open(scheduleIndexFilename, 'w') + scheduleFile = open(scheduleIndexFilename, 'w+') if scheduleFile: scheduleFile.write(indexStr + '\n') scheduleFile.close() @@ -1337,7 +1337,7 @@ def createReportPost(baseDir: str, if os.path.isfile(newReportFile): continue try: - with open(newReportFile, 'w') as fp: + with open(newReportFile, 'w+') as fp: fp.write(toUrl + '/moderation') except BaseException: pass diff --git a/shares.py b/shares.py index a20fb8055..af300d223 100644 --- a/shares.py +++ b/shares.py @@ -181,7 +181,7 @@ def addShare(baseDir: str, if not os.path.isfile(newShareFile): nickname = handle.split('@')[0] try: - with open(newShareFile, 'w') as fp: + with open(newShareFile, 'w+') as fp: fp.write(httpPrefix + '://' + domainFull + '/users/' + nickname + '/tlshares') except BaseException: diff --git a/tests.py b/tests.py index 12faa4634..0d47268dd 100644 --- a/tests.py +++ b/tests.py @@ -101,7 +101,8 @@ def testHttpsigBase(withDigest): port = 5576 password = 'SuperSecretPassword' privateKeyPem, publicKeyPem, person, wfEndpoint = \ - createPerson(path, nickname, domain, port, httpPrefix, False, password) + createPerson(path, nickname, domain, port, httpPrefix, + False, False, password) assert privateKeyPem messageBodyJson = { "a key": "a value", @@ -253,7 +254,8 @@ def createServerAlice(path: str, domain: str, port: int, accountMaxPostsPerDay = 1000 allowDeletion = True privateKeyPem, publicKeyPem, person, wfEndpoint = \ - createPerson(path, nickname, domain, port, httpPrefix, True, password) + createPerson(path, nickname, domain, port, httpPrefix, True, + False, password) deleteAllPosts(path, nickname, domain, 'inbox') deleteAllPosts(path, nickname, domain, 'outbox') assert setSkillLevel(path, nickname, domain, 'hacking', 90) @@ -289,7 +291,8 @@ def createServerAlice(path: str, domain: str, port: int, noreply, nolike, nopics, noannounce, cw, ocapAlways, proxyType, maxReplies, domainMaxPostsPerDay, accountMaxPostsPerDay, - allowDeletion, True, True, False, sendThreads, False) + allowDeletion, True, True, False, sendThreads, False, + False) def createServerBob(path: str, domain: str, port: int, @@ -317,7 +320,8 @@ def createServerBob(path: str, domain: str, port: int, accountMaxPostsPerDay = 1000 allowDeletion = True privateKeyPem, publicKeyPem, person, wfEndpoint = \ - createPerson(path, nickname, domain, port, httpPrefix, True, password) + createPerson(path, nickname, domain, port, httpPrefix, True, + False, password) deleteAllPosts(path, nickname, domain, 'inbox') deleteAllPosts(path, nickname, domain, 'outbox') assert setRole(path, nickname, domain, 'bandname', 'bass player') @@ -352,7 +356,8 @@ def createServerBob(path: str, domain: str, port: int, noreply, nolike, nopics, noannounce, cw, ocapAlways, proxyType, maxReplies, domainMaxPostsPerDay, accountMaxPostsPerDay, - allowDeletion, True, True, False, sendThreads, False) + allowDeletion, True, True, False, sendThreads, False, + False) def createServerEve(path: str, domain: str, port: int, federationList: [], @@ -375,7 +380,8 @@ def createServerEve(path: str, domain: str, port: int, federationList: [], maxReplies = 64 allowDeletion = True privateKeyPem, publicKeyPem, person, wfEndpoint = \ - createPerson(path, nickname, domain, port, httpPrefix, True, password) + createPerson(path, nickname, domain, port, httpPrefix, True, + False, password) deleteAllPosts(path, nickname, domain, 'inbox') deleteAllPosts(path, nickname, domain, 'outbox') global testServerEveRunning @@ -391,7 +397,7 @@ def createServerEve(path: str, domain: str, port: int, federationList: [], httpPrefix, federationList, maxMentions, maxEmoji, False, noreply, nolike, nopics, noannounce, cw, ocapAlways, proxyType, maxReplies, allowDeletion, True, True, False, - sendThreads, False) + sendThreads, False, False) def testPostMessageBetweenServers(): @@ -840,15 +846,15 @@ def testFollowersOfPerson(): os.mkdir(baseDir) os.chdir(baseDir) createPerson(baseDir, nickname, domain, port, - httpPrefix, True, password) + httpPrefix, True, False, password) createPerson(baseDir, 'maxboardroom', domain, port, - httpPrefix, True, password) + httpPrefix, True, False, password) createPerson(baseDir, 'ultrapancake', domain, port, - httpPrefix, True, password) + httpPrefix, True, False, password) createPerson(baseDir, 'drokk', domain, port, - httpPrefix, True, password) + httpPrefix, True, False, password) createPerson(baseDir, 'sausagedog', domain, port, - httpPrefix, True, password) + httpPrefix, True, False, password) clearFollows(baseDir, nickname, domain) followPerson(baseDir, nickname, domain, 'maxboardroom', domain, @@ -889,15 +895,16 @@ def testNoOfFollowersOnDomain(): shutil.rmtree(baseDir) os.mkdir(baseDir) os.chdir(baseDir) - createPerson(baseDir, nickname, domain, port, httpPrefix, True, password) + createPerson(baseDir, nickname, domain, port, httpPrefix, True, + False, password) createPerson(baseDir, 'maxboardroom', otherdomain, port, - httpPrefix, True, password) + httpPrefix, True, False, password) createPerson(baseDir, 'ultrapancake', otherdomain, port, - httpPrefix, True, password) + httpPrefix, True, False, password) createPerson(baseDir, 'drokk', otherdomain, port, - httpPrefix, True, password) + httpPrefix, True, False, password) createPerson(baseDir, 'sausagedog', otherdomain, port, - httpPrefix, True, password) + httpPrefix, True, False, password) followPerson(baseDir, 'drokk', otherdomain, nickname, domain, federationList, False) @@ -949,7 +956,8 @@ def testGroupFollowers(): shutil.rmtree(baseDir) os.mkdir(baseDir) os.chdir(baseDir) - createPerson(baseDir, nickname, domain, port, httpPrefix, True, password) + createPerson(baseDir, nickname, domain, port, httpPrefix, True, + False, password) clearFollowers(baseDir, nickname, domain) followerOfPerson(baseDir, nickname, domain, 'badger', 'wild.domain', @@ -992,7 +1000,8 @@ def testFollows(): shutil.rmtree(baseDir) os.mkdir(baseDir) os.chdir(baseDir) - createPerson(baseDir, nickname, domain, port, httpPrefix, True, password) + createPerson(baseDir, nickname, domain, port, httpPrefix, True, + False, password) clearFollows(baseDir, nickname, domain) followPerson(baseDir, nickname, domain, 'badger', 'wild.com', @@ -1072,7 +1081,7 @@ def testCreatePerson(): privateKeyPem, publicKeyPem, person, wfEndpoint = \ createPerson(baseDir, nickname, domain, port, - httpPrefix, True, password) + httpPrefix, True, False, password) assert os.path.isfile(baseDir + '/accounts/passwords') deleteAllPosts(baseDir, nickname, domain, 'inbox') deleteAllPosts(baseDir, nickname, domain, 'outbox') @@ -1106,10 +1115,10 @@ def testDelegateRoles(): privateKeyPem, publicKeyPem, person, wfEndpoint = \ createPerson(baseDir, nickname, domain, port, - httpPrefix, True, password) + httpPrefix, True, False, password) privateKeyPem, publicKeyPem, person, wfEndpoint = \ createPerson(baseDir, nicknameDelegated, domain, port, - httpPrefix, True, 'insecure') + httpPrefix, True, False, 'insecure') httpPrefix = 'http' project = 'artechoke' @@ -1702,7 +1711,7 @@ def testAddEmoji(): os.chdir(baseDir) privateKeyPem, publicKeyPem, person, wfEndpoint = \ createPerson(baseDir, nickname, domain, port, - httpPrefix, True, 'password') + httpPrefix, True, False, 'password') contentModified = \ addHtmlTags(baseDir, httpPrefix, nickname, domain, content, diff --git a/theme.py b/theme.py index 786f49584..c1a323c17 100644 --- a/theme.py +++ b/theme.py @@ -105,7 +105,7 @@ def setThemeFromDict(baseDir: str, name: str, themeParams: {}) -> None: for paramName, paramValue in themeParams.items(): css = setCSSparam(css, paramName, paramValue) filename = baseDir + '/' + filename - with open(filename, 'w') as cssfile: + with open(filename, 'w+') as cssfile: cssfile.write(css) @@ -124,11 +124,11 @@ def enableGrayscale(baseDir: str) -> None: css.replace('body, html {', 'body, html {\n filter: grayscale(100%);') filename = baseDir + '/' + filename - with open(filename, 'w') as cssfile: + with open(filename, 'w+') as cssfile: cssfile.write(css) grayscaleFilename = baseDir + '/accounts/.grayscale' if not os.path.isfile(grayscaleFilename): - with open(grayscaleFilename, 'w') as grayfile: + with open(grayscaleFilename, 'w+') as grayfile: grayfile.write(' ') @@ -146,7 +146,7 @@ def disableGrayscale(baseDir: str) -> None: css = \ css.replace('\n filter: grayscale(100%);', '') filename = baseDir + '/' + filename - with open(filename, 'w') as cssfile: + with open(filename, 'w+') as cssfile: cssfile.write(css) grayscaleFilename = baseDir + '/accounts/.grayscale' if os.path.isfile(grayscaleFilename): @@ -187,7 +187,7 @@ def setCustomFont(baseDir: str): customFontType + "')") css = setCSSparam(css, "*font-family", "'CustomFont'") filename = baseDir + '/' + filename - with open(filename, 'w') as cssfile: + with open(filename, 'w+') as cssfile: cssfile.write(css) diff --git a/utils.py b/utils.py index c53811f26..abdb67be7 100644 --- a/utils.py +++ b/utils.py @@ -51,7 +51,7 @@ def saveJson(jsonObject: {}, filename: str) -> bool: tries = 0 while tries < 5: try: - with open(filename, 'w') as fp: + with open(filename, 'w+') as fp: fp.write(json.dumps(jsonObject)) return True except BaseException: diff --git a/webinterface.py b/webinterface.py index 85faa020b..ecc49606b 100644 --- a/webinterface.py +++ b/webinterface.py @@ -2242,11 +2242,27 @@ def htmlNewPost(mediaInstance: bool, translate: {}, return newPostForm +def getFontFromCss(css: str) -> (str, str): + """Returns the font name and format + """ + if ' url(' not in css: + return None, None + fontName = css.split(" url('")[1].split("')")[0] + fontFormat = css.split(" format('")[1].split("')")[0] + return fontName, fontFormat + + def htmlHeader(cssFilename: str, css: str, lang='en') -> str: htmlStr = '\n' htmlStr += '\n' - htmlStr += ' \n' - htmlStr += ' \n' + htmlStr += ' \n' + htmlStr += ' \n' + fontName, fontFormat = getFontFromCss(css) + if fontName: + htmlStr += ' \n' + htmlStr += ' \n' + htmlStr += ' \n' htmlStr += ' \n' return htmlStr @@ -3321,7 +3337,7 @@ def saveIndividualPostAsHtmlToCache(baseDir: str, os.mkdir(htmlPostCacheDir) try: - with open(cachedPostFilename, 'w') as fp: + with open(cachedPostFilename, 'w+') as fp: fp.write(postHtml) return True except Exception as e: