diff --git a/daemon.py b/daemon.py index b147c100d..3008469f4 100644 --- a/daemon.py +++ b/daemon.py @@ -181,6 +181,11 @@ from webapp_search import htmlSearchEmojiTextEntry from webapp_search import htmlSearch from webapp_hashtagswarm import getHashtagCategoriesFeed from webapp_hashtagswarm import htmlSearchHashtagCategory +from webapp_welcome import welcomeScreenIsComplete +from webapp_welcome import htmlWelcomeScreen +from webapp_welcome import isWelcomeScreenComplete +from webapp_welcome_profile import htmlWelcomeProfile +from webapp_welcome_final import htmlWelcomeFinal from shares import getSharesFeedForPerson from shares import addShare from shares import removeShare @@ -4042,6 +4047,21 @@ class PubServer(BaseHTTPRequestHandler): ' image or font could not be saved to ' + postImageFilename) + postBytesStr = postBytes.decode('utf-8') + redirectPath = '' + checkNameAndBio = False + if 'name="previewAvatar"' in postBytesStr: + redirectPath = '/welcome_profile' + elif 'name="initialWelcomeScreen"' in postBytesStr: + redirectPath = '/welcome' + elif 'name="finalWelcomeScreen"' in postBytesStr: + checkNameAndBio = True + redirectPath = '/welcome_final' + elif 'name="welcomeCompleteButton"' in postBytesStr: + redirectPath = '/' + self.server.defaultTimeline + welcomeScreenIsComplete(self.server.baseDir, nickname, + self.server.domain) + # extract all of the text fields into a dict fields = \ extractTextFieldsInPOST(postBytes, boundary, debug) @@ -4172,7 +4192,12 @@ class PubServer(BaseHTTPRequestHandler): actorJson['name'] = displayName else: actorJson['name'] = nickname + if checkNameAndBio: + redirectPath = 'previewAvatar' actorChanged = True + else: + if checkNameAndBio: + redirectPath = 'previewAvatar' # change media instance status if fields.get('mediaInstance'): @@ -4535,10 +4560,12 @@ class PubServer(BaseHTTPRequestHandler): for tagName, tag in actorTags.items(): actorJson['tag'].append(tag) actorChanged = True + else: + if checkNameAndBio: + redirectPath = 'previewAvatar' else: - if actorJson['summary']: - actorJson['summary'] = '' - actorChanged = True + if checkNameAndBio: + redirectPath = 'previewAvatar' adminNickname = \ getConfigParam(baseDir, 'admin') @@ -5022,7 +5049,8 @@ class PubServer(BaseHTTPRequestHandler): i2pDomain): actorStr = \ 'http://' + i2pDomain + usersPath - self._redirect_headers(actorStr, cookie, callingDomain) + self._redirect_headers(actorStr + redirectPath, + cookie, callingDomain) self.server.POSTbusy = False def _progressiveWebAppManifest(self, callingDomain: str, @@ -10345,6 +10373,23 @@ class PubServer(BaseHTTPRequestHandler): if '/users/' in self.path: usersInPath = True + # redirect to the welcome screen + if htmlGET and authorized and usersInPath and \ + '/welcome' not in self.path: + nickname = self.path.split('/users/')[1] + if '/' in nickname: + nickname = nickname.split('/')[0] + if '?' in nickname: + nickname = nickname.split('?')[0] + if nickname == self.authorizedNickname and \ + self.path != '/users/' + nickname: + if not isWelcomeScreenComplete(self.server.baseDir, + nickname, + self.server.domain): + self._redirect_headers('/users/' + nickname + '/welcome', + cookie, callingDomain) + return + if not htmlGET and \ usersInPath and self.path.endswith('/pinned'): nickname = self.path.split('/users/')[1] @@ -10670,6 +10715,84 @@ class PubServer(BaseHTTPRequestHandler): 'show about screen done', 'robots txt') + # the initial welcome screen after first logging in + if htmlGET and authorized and \ + '/users/' in self.path and self.path.endswith('/welcome'): + nickname = self.path.split('/users/')[1] + if '/' in nickname: + nickname = nickname.split('/')[0] + if not isWelcomeScreenComplete(self.server.baseDir, + nickname, + self.server.domain): + msg = \ + htmlWelcomeScreen(self.server.baseDir, nickname, + self.server.systemLanguage, + self.server.translate) + msg = msg.encode('utf-8') + msglen = len(msg) + self._login_headers('text/html', msglen, callingDomain) + self._write(msg) + self._benchmarkGETtimings(GETstartTime, GETtimings, + 'following accounts done', + 'show welcome screen') + return + else: + self.path = self.path.replace('/welcome', '') + + # the welcome screen which allows you to set an avatar image + if htmlGET and authorized and \ + '/users/' in self.path and self.path.endswith('/welcome_profile'): + nickname = self.path.split('/users/')[1] + if '/' in nickname: + nickname = nickname.split('/')[0] + if not isWelcomeScreenComplete(self.server.baseDir, + nickname, + self.server.domain): + msg = \ + htmlWelcomeProfile(self.server.baseDir, nickname, + self.server.domain, + self.server.httpPrefix, + self.server.domainFull, + self.server.systemLanguage, + self.server.translate) + msg = msg.encode('utf-8') + msglen = len(msg) + self._login_headers('text/html', msglen, callingDomain) + self._write(msg) + self._benchmarkGETtimings(GETstartTime, GETtimings, + 'show welcome screen', + 'show welcome profile screen') + return + else: + self.path = self.path.replace('/welcome_profile', '') + + # the final welcome screen + if htmlGET and authorized and \ + '/users/' in self.path and self.path.endswith('/welcome_final'): + nickname = self.path.split('/users/')[1] + if '/' in nickname: + nickname = nickname.split('/')[0] + if not isWelcomeScreenComplete(self.server.baseDir, + nickname, + self.server.domain): + msg = \ + htmlWelcomeFinal(self.server.baseDir, nickname, + self.server.domain, + self.server.httpPrefix, + self.server.domainFull, + self.server.systemLanguage, + self.server.translate) + msg = msg.encode('utf-8') + msglen = len(msg) + self._login_headers('text/html', msglen, callingDomain) + self._write(msg) + self._benchmarkGETtimings(GETstartTime, GETtimings, + 'show welcome profile screen', + 'show welcome final screen') + return + else: + self.path = self.path.replace('/welcome_final', '') + # if not authorized then show the login screen if htmlGET and self.path != '/login' and \ not self._pathIsImage(self.path) and \ diff --git a/defaultwelcome/final_ar.md b/defaultwelcome/final_ar.md new file mode 100644 index 000000000..0d663d636 --- /dev/null +++ b/defaultwelcome/final_ar.md @@ -0,0 +1,9 @@ +### تهانينا! +أنت الآن جاهز لبدء استخدام Epicyon. هذه مساحة اجتماعية خاضعة للإشراف ، لذا يرجى التأكد من الالتزام بـ [شروط الخدمة](/terms) الخاصة بنا ، واستمتع. + +#### تلميحات +استخدم رمز **المكبر** 🔍 للبحث عن مقابض الكون المشترك ومتابعة الأشخاص. + +يؤدي تحديد **الشعار في الجزء العلوي** من الشاشة إلى التبديل بين عرض المخطط الزمني وملف التعريف الخاص بك. + +لن يتم تحديث الشاشة تلقائيًا عند وصول المنشورات ، لذا استخدم **F5** أو زر البريد الوارد للتحديث. diff --git a/defaultwelcome/final_ca.md b/defaultwelcome/final_ca.md new file mode 100644 index 000000000..deff371ba --- /dev/null +++ b/defaultwelcome/final_ca.md @@ -0,0 +1,9 @@ +### Enhorabona! +Ja esteu a punt per començar a utilitzar Epicyon. Aquest és un espai social moderat, així que assegureu-vos de complir les nostres [condicions del servei](/terms) i divertir-vos. + +#### Consells +Utilitzeu la icona de **lupa** 🔍 per cercar manetes fedivers i seguir les persones. + +Si seleccioneu el **bàner a la part superior** de la pantalla es canvia entre la visualització de la línia de temps i el vostre perfil. + +La pantalla no s'actualitzarà automàticament quan arribin les publicacions, així que utilitzeu **F5** o el botó **Safata d'entrada** per actualitzar. diff --git a/defaultwelcome/final_cy.md b/defaultwelcome/final_cy.md new file mode 100644 index 000000000..12211aa7a --- /dev/null +++ b/defaultwelcome/final_cy.md @@ -0,0 +1,9 @@ +### Llongyfarchiadau! +Rydych nawr yn barod i ddechrau defnyddio Epicyon. Mae hwn yn ofod cymdeithasol wedi'i gymedroli, felly gwnewch yn siŵr eich bod yn cadw at ein [telerau gwasanaeth](/terms), a chael hwyl. + +#### Awgrymiadau +Defnyddiwch yr eicon **chwyddwydr** 🔍 i chwilio am ddolenni bwydo a dilyn pobl. + +Mae dewis y faner **ar frig** y sgrin yn newid rhwng yr olygfa llinell amser a'ch proffil. + +Ni fydd y sgrin yn adnewyddu'n awtomatig pan fydd pyst yn cyrraedd, felly defnyddiwch **F5** neu'r botwm **Mewnflwch** i adnewyddu. diff --git a/defaultwelcome/final_en.md b/defaultwelcome/final_en.md new file mode 100644 index 000000000..81aad26cd --- /dev/null +++ b/defaultwelcome/final_en.md @@ -0,0 +1,9 @@ +### Congratulations! +You are now ready to begin using Epicyon. This is a moderated social space, so please make sure to abide by our [terms of service](/terms), and have fun. + +#### Hints +Use the **magnifier** icon 🔍 to search for fediverse handles and follow people. + +Selecting the **banner at the top** of the screen switches between timeline view and your profile. + +The screen will not automatically refresh when posts arrive, so use **F5** or the **Inbox** button to refresh. diff --git a/defaultwelcome/final_es.md b/defaultwelcome/final_es.md new file mode 100644 index 000000000..9050750a9 --- /dev/null +++ b/defaultwelcome/final_es.md @@ -0,0 +1,9 @@ +### ¡Felicidades! +Ahora está listo para comenzar a usar Epicyon. Este es un espacio social moderado, así que asegúrese de cumplir con nuestros [términos de servicio](/terms) y diviértase. + +#### Sugerencias +Utilice el icono de **lupa** 🔍 para buscar identificadores de fediverse y seguir a las personas. + +Al seleccionar el **banner en la parte superior** de la pantalla, se cambia entre la vista de línea de tiempo y su perfil. + +La pantalla no se actualizará automáticamente cuando lleguen las publicaciones, así que use **F5** o el botón **Bandeja de entrada** para actualizar. diff --git a/defaultwelcome/final_fr.md b/defaultwelcome/final_fr.md new file mode 100644 index 000000000..272133245 --- /dev/null +++ b/defaultwelcome/final_fr.md @@ -0,0 +1,9 @@ +### Toutes nos félicitations! +Vous êtes maintenant prêt à commencer à utiliser Epicyon. Il s'agit d'un espace social modéré, alors assurez-vous de respecter nos [conditions d'utilisation](/terms) et amusez-vous. + +#### Conseils +Utilisez l'icône **loupe** 🔍 pour rechercher des poignées fediverse et suivre les gens. + +La sélection de la **bannière en haut** de l'écran bascule entre la vue chronologique et votre profil. + +L'écran ne s'actualisera pas automatiquement à l'arrivée des messages, utilisez donc **F5** ou le bouton **Boîte de réception** pour actualiser. diff --git a/defaultwelcome/final_ga.md b/defaultwelcome/final_ga.md new file mode 100644 index 000000000..b8c1e576b --- /dev/null +++ b/defaultwelcome/final_ga.md @@ -0,0 +1,9 @@ +### Comhghairdeas! +Tá tú réidh anois chun Epicyon a úsáid. Is spás sóisialta measartha é seo, mar sin déan cinnte cloí lenár [dtéarmaí seirbhíse](/terms), agus spraoi a bheith agat. + +#### Leideanna +Úsáid an deilbhín **formhéadaitheoir** chun cuardach a dhéanamh ar láimhseálacha beathaithe agus lean daoine. + +Ag roghnú an bhratach **ag barr** na lasca scáileáin idir amharc amlíne agus do phróifíl. + +Ní dhéanfaidh an scáileán athnuachan go huathoibríoch nuair a thiocfaidh na poist, mar sin bain úsáid as **F5** nó an cnaipe **Bosca Isteach** chun athnuachan a dhéanamh. diff --git a/defaultwelcome/final_hi.md b/defaultwelcome/final_hi.md new file mode 100644 index 000000000..971af274c --- /dev/null +++ b/defaultwelcome/final_hi.md @@ -0,0 +1,9 @@ +### बधाई हो! +अब आप एपिसकॉन का उपयोग शुरू करने के लिए तैयार हैं। यह एक मध्यम सामाजिक स्थान है, इसलिए कृपया हमारी [सेवा की शर्तों](/terms) का पालन करना सुनिश्चित करें, और मज़े करें। + +#### संकेत +फ़ेडरिवर्स हैंडल की खोज करने और लोगों का अनुसरण करने के लिए **आवर्धक आइकन** का उपयोग करें। + +समय दृश्य और आपकी प्रोफ़ाइल के बीच स्क्रीन स्विच के शीर्ष **पर स्थित** बैनर का चयन करना। + +पोस्ट आने पर स्क्रीन अपने आप रिफ्रेश नहीं होगी, इसलिए रीफ्रेश करने के लिए **F5** या **इनबॉक्स** बटन का उपयोग करें। diff --git a/defaultwelcome/final_it.md b/defaultwelcome/final_it.md new file mode 100644 index 000000000..818b231f9 --- /dev/null +++ b/defaultwelcome/final_it.md @@ -0,0 +1,9 @@ +### Congratulazioni! +Ora sei pronto per iniziare a utilizzare Epicyon. Questo è uno spazio social moderato, quindi assicurati di rispettare i nostri [termini di servizio](/terms) e divertiti. + +#### Suggerimenti +Usa l'icona **lente d'ingrandimento** 🔍 per cercare gli handle di fediverse e seguire le persone. + +Selezionando il **banner nella parte superiore** dello schermo si passa dalla visualizzazione della sequenza temporale al tuo profilo. + +La schermata non si aggiornerà automaticamente all'arrivo dei post, quindi utilizza **F5** o il pulsante **Posta in arrivo** per aggiornare. diff --git a/defaultwelcome/final_ja.md b/defaultwelcome/final_ja.md new file mode 100644 index 000000000..40b4e2575 --- /dev/null +++ b/defaultwelcome/final_ja.md @@ -0,0 +1,9 @@ +### おめでとう! +これで、Epicyonの使用を開始する準備が整いました。 適度な社交空間ですので、必ず [利用規約](/terms) を遵守して楽しんでください。 + +#### ヒント +**拡大鏡** アイコン🔍を使用して、fediverseハンドルを検索し、人々をフォローします。 + +画面の上部にある **バナー** を選択すると、タイムラインビューとプロファイルが切り替わります。 + +投稿が到着しても画面は自動的に更新されないため、 **F5** または **受信トレイ** ボタンを使用して更新してください。 diff --git a/defaultwelcome/final_oc.md b/defaultwelcome/final_oc.md new file mode 100644 index 000000000..ef9eb2601 --- /dev/null +++ b/defaultwelcome/final_oc.md @@ -0,0 +1,9 @@ +# Congratulations! +You are now ready to begin using Epicyon. This is a moderated social space, so please make sure to abide by our [terms of service](/terms), and have fun. + +### Hints +Use the **magnifier** icon 🔍 to search for fediverse handles and follow people. + +Selecting the **banner at the top** of the screen switches between timeline view and your profile. + +The screen will not automatically refresh when posts arrive, so use **F5** or the **Inbox** button to refresh. diff --git a/defaultwelcome/final_pt.md b/defaultwelcome/final_pt.md new file mode 100644 index 000000000..3f8cdf87b --- /dev/null +++ b/defaultwelcome/final_pt.md @@ -0,0 +1,9 @@ +# Parabéns! +Agora você está pronto para começar a usar o Epicyon. Este é um espaço social moderado, portanto, certifique-se de seguir nossos [termos de serviço](/terms) e divirta-se. + +### Dicas +Use o ícone de **lupa** 🔍 para pesquisar as alças do fediverse e seguir pessoas. + +Selecionar o **banner na parte superior** da tela alterna entre a visualização da linha do tempo e seu perfil. + +A tela não será atualizada automaticamente quando as postagens chegarem, então use **F5** ou o botão **Caixa de entrada** para atualizar. diff --git a/defaultwelcome/final_ru.md b/defaultwelcome/final_ru.md new file mode 100644 index 000000000..31e11700f --- /dev/null +++ b/defaultwelcome/final_ru.md @@ -0,0 +1,9 @@ +### Поздравляю! +Теперь вы готовы начать использовать Epicyon. Это модерируемое социальное пространство, поэтому, пожалуйста, соблюдайте наши [условия обслуживания](/terms) и получайте удовольствие. + +#### Подсказки +Используйте значок **лупы** 🔍, чтобы искать нужные метки и следить за людьми. + +При выборе **баннера вверху** экрана выполняется переключение между представлением временной шкалы и вашим профилем. + +Экран не обновляется автоматически при поступлении сообщений, поэтому используйте **F5** или кнопку **Входящие** для обновления. diff --git a/defaultwelcome/final_zh.md b/defaultwelcome/final_zh.md new file mode 100644 index 000000000..1cd50c41b --- /dev/null +++ b/defaultwelcome/final_zh.md @@ -0,0 +1,9 @@ +### 恭喜你! +您现在可以开始使用Epicyon。 这是一个温和的社交空间,因此请务必遵守我们的[服务条款](/terms),并从中获得乐趣。 + +####提示 +使用放大镜图标search搜索fed性的手柄并关注他人。 + +选择屏幕顶部的横幅广告可在时间轴视图和个人资料之间切换。 + +帖子到达时,屏幕不会自动刷新,因此请使用F5或“收件箱”按钮刷新。 diff --git a/defaultwelcome/profile_ar.md b/defaultwelcome/profile_ar.md new file mode 100644 index 000000000..0d0ed4ab9 --- /dev/null +++ b/defaultwelcome/profile_ar.md @@ -0,0 +1,2 @@ +### اعدادات الحساب +حدد صورتك الرمزية وأضف اسمك ووصفك. استخدم صورة رمزية صغيرة (على سبيل المثال ، 128 × 128 بكسل) بحيث يمكن تنزيلها بسرعة. diff --git a/defaultwelcome/profile_ca.md b/defaultwelcome/profile_ca.md new file mode 100644 index 000000000..90c5d6c85 --- /dev/null +++ b/defaultwelcome/profile_ca.md @@ -0,0 +1,2 @@ +### Configuració del compte +Seleccioneu la vostra imatge d’avatar i afegiu el vostre nom i la vostra descripció. Utilitzeu una imatge d’avatar petita (per exemple, 128x128 píxels) per baixar-la ràpidament. diff --git a/defaultwelcome/profile_cy.md b/defaultwelcome/profile_cy.md new file mode 100644 index 000000000..92ced863e --- /dev/null +++ b/defaultwelcome/profile_cy.md @@ -0,0 +1,2 @@ +### Gosod Cyfrif +Dewiswch eich delwedd avatar ac ychwanegwch eich enw a'ch disgrifiad. Defnyddiwch ddelwedd avatar fach (ee 128x128 picsel) fel ei bod yn gyflym i'w lawrlwytho. diff --git a/defaultwelcome/profile_de.md b/defaultwelcome/profile_de.md new file mode 100644 index 000000000..668da69ce --- /dev/null +++ b/defaultwelcome/profile_de.md @@ -0,0 +1,2 @@ +### Kontoeinrichtung +Wählen Sie Ihr Avatar-Bild aus und fügen Sie Ihren Namen und Ihre Beschreibung hinzu. Verwenden Sie ein kleines Avatar-Bild (z. B. 128 x 128 Pixel), damit es schnell heruntergeladen werden kann. diff --git a/defaultwelcome/profile_en.md b/defaultwelcome/profile_en.md new file mode 100644 index 000000000..2a1768332 --- /dev/null +++ b/defaultwelcome/profile_en.md @@ -0,0 +1,2 @@ +### Account Setup +Select your avatar image and add your name and description. Use a small avatar image (eg. 128x128 pixels) so that it's quick to download. diff --git a/defaultwelcome/profile_es.md b/defaultwelcome/profile_es.md new file mode 100644 index 000000000..63bac75b9 --- /dev/null +++ b/defaultwelcome/profile_es.md @@ -0,0 +1,2 @@ +### Configuracion de cuenta +Seleccione su imagen de avatar y agregue su nombre y descripción. Utilice una imagen de avatar pequeña (por ejemplo, 128x128 píxeles) para que se descargue rápidamente. diff --git a/defaultwelcome/profile_fr.md b/defaultwelcome/profile_fr.md new file mode 100644 index 000000000..56f93d648 --- /dev/null +++ b/defaultwelcome/profile_fr.md @@ -0,0 +1,2 @@ +### Configuration du compte +Sélectionnez l'image de votre avatar et ajoutez votre nom et votre description. Utilisez une petite image d'avatar (par exemple, 128x128 pixels) pour un téléchargement rapide. diff --git a/defaultwelcome/profile_ga.md b/defaultwelcome/profile_ga.md new file mode 100644 index 000000000..b0019e644 --- /dev/null +++ b/defaultwelcome/profile_ga.md @@ -0,0 +1,2 @@ +### Socrú Cuntas +Roghnaigh d’íomhá avatar agus cuir d’ainm agus do thuairisc leis. Úsáid íomhá bheag avatar (m.sh. 128x128 picteilín) ionas go mbeidh sí gasta le híoslódáil. diff --git a/defaultwelcome/profile_hi.md b/defaultwelcome/profile_hi.md new file mode 100644 index 000000000..5190b999d --- /dev/null +++ b/defaultwelcome/profile_hi.md @@ -0,0 +1,2 @@ +### खाता स्थापित करना +अपनी अवतार छवि का चयन करें और अपना नाम और विवरण जोड़ें। एक छोटी अवतार छवि (जैसे। 128x128 पिक्सेल) का उपयोग करें ताकि यह डाउनलोड करने में तेज हो। diff --git a/defaultwelcome/profile_it.md b/defaultwelcome/profile_it.md new file mode 100644 index 000000000..97487bc62 --- /dev/null +++ b/defaultwelcome/profile_it.md @@ -0,0 +1,2 @@ +### Configurazione dell'account +Seleziona la tua immagine avatar e aggiungi il tuo nome e la descrizione. Usa una piccola immagine avatar (es. 128x128 pixel) in modo che sia veloce da scaricare. diff --git a/defaultwelcome/profile_ja.md b/defaultwelcome/profile_ja.md new file mode 100644 index 000000000..d63a80d55 --- /dev/null +++ b/defaultwelcome/profile_ja.md @@ -0,0 +1,2 @@ +### アカウントの設定 +アバター画像を選択し、名前と説明を追加します。 小さなアバター画像(128x128ピクセルなど)を使用して、すばやくダウンロードできるようにします。 diff --git a/defaultwelcome/profile_oc.md b/defaultwelcome/profile_oc.md new file mode 100644 index 000000000..10d1e09e3 --- /dev/null +++ b/defaultwelcome/profile_oc.md @@ -0,0 +1,2 @@ +## Account Setup +Select your avatar image and add your name and description. Use a small avatar image (eg. 128x128 pixels) so that it's quick to download. diff --git a/defaultwelcome/profile_pt.md b/defaultwelcome/profile_pt.md new file mode 100644 index 000000000..9371c6ad3 --- /dev/null +++ b/defaultwelcome/profile_pt.md @@ -0,0 +1,2 @@ +## Configuração da conta +Selecione sua imagem de avatar e adicione seu nome e descrição. Use uma pequena imagem de avatar (por exemplo, 128x128 pixels) para que o download seja rápido. diff --git a/defaultwelcome/profile_ru.md b/defaultwelcome/profile_ru.md new file mode 100644 index 000000000..b0d53a568 --- /dev/null +++ b/defaultwelcome/profile_ru.md @@ -0,0 +1,2 @@ +### Настройка учетной записи +Выберите изображение своего аватара и добавьте свое имя и описание. Используйте небольшое изображение аватара (например, 128x128 пикселей), чтобы его можно было быстро загрузить. diff --git a/defaultwelcome/profile_zh.md b/defaultwelcome/profile_zh.md new file mode 100644 index 000000000..33a1b0a6d --- /dev/null +++ b/defaultwelcome/profile_zh.md @@ -0,0 +1,2 @@ +### 帐户设定 +选择您的头像图片并添加您的姓名和描述。 使用较小的头像图片(例如128x128像素),以便快速下载。 diff --git a/defaultwelcome/welcome_ar.md b/defaultwelcome/welcome_ar.md new file mode 100644 index 000000000..8e88deb0a --- /dev/null +++ b/defaultwelcome/welcome_ar.md @@ -0,0 +1,6 @@ +### مرحبًا بكم في INSTANCE +هذا خادم ActivityPub مصمم للاستضافة الذاتية السهلة لعدد قليل من الأشخاص على أنظمة منخفضة الطاقة ، مثل أجهزة الكمبيوتر ذات اللوحة الواحدة أو أجهزة الكمبيوتر المحمولة القديمة. + +قم بتشغيل وجودك على الشبكة الاجتماعية بالطريقة التي تريدها ، وداعًا لشركة Big Tech. + +الآن ، لنبدأ ... diff --git a/defaultwelcome/welcome_ca.md b/defaultwelcome/welcome_ca.md new file mode 100644 index 000000000..0721e7e14 --- /dev/null +++ b/defaultwelcome/welcome_ca.md @@ -0,0 +1,6 @@ +### Benvingut a INSTANCE +Es tracta d’un servidor ActivityPub dissenyat per allotjar fàcilment algunes persones en sistemes de poca potència, com ara ordinadors de placa única o portàtils antics. + +Gestioneu la vostra pròpia presència a la xarxa social com vulgueu i acomiadeu-vos de Big Tech. + +Ara, comencem ... diff --git a/defaultwelcome/welcome_cy.md b/defaultwelcome/welcome_cy.md new file mode 100644 index 000000000..7596a7927 --- /dev/null +++ b/defaultwelcome/welcome_cy.md @@ -0,0 +1,6 @@ +### Croeso i INSTANCE +Gweinydd ActivityPub yw hwn sydd wedi'i gynllunio ar gyfer hunan-letya ychydig o bobl ar systemau pŵer isel yn hawdd, fel cyfrifiaduron bwrdd sengl neu hen gliniaduron. + +Rhedeg eich presenoldeb rhwydwaith cymdeithasol eich hun yn y ffordd rydych chi eisiau, a ffarwelio â Big Tech. + +Nawr, gadewch i ni fynd ... diff --git a/defaultwelcome/welcome_de.md b/defaultwelcome/welcome_de.md new file mode 100644 index 000000000..f1dedb95b --- /dev/null +++ b/defaultwelcome/welcome_de.md @@ -0,0 +1,6 @@ +### Willkommen bei INSTANCE +Dies ist ein ActivityPub-Server, der für das einfache Selbsthosting einiger weniger Personen auf Systemen mit geringem Stromverbrauch wie Single-Board-Computern oder alten Laptops entwickelt wurde. + +Führen Sie Ihre eigene soziale Netzwerkpräsenz so, wie Sie möchten, und verabschieden Sie sich von Big Tech. + +Jetzt geht's los ... diff --git a/defaultwelcome/welcome_en.md b/defaultwelcome/welcome_en.md new file mode 100644 index 000000000..5d942a9a5 --- /dev/null +++ b/defaultwelcome/welcome_en.md @@ -0,0 +1,6 @@ +### Welcome to INSTANCE +This is an ActivityPub server designed for easy self-hosting of a few people on low power systems, such as single board computers or old laptops. + +Run your own social network presence the way you want to, and say goodbye to Big Tech. + +Now, lets get going... diff --git a/defaultwelcome/welcome_es.md b/defaultwelcome/welcome_es.md new file mode 100644 index 000000000..f9ba98454 --- /dev/null +++ b/defaultwelcome/welcome_es.md @@ -0,0 +1,6 @@ +### Bienvenido a INSTANCE +Este es un servidor ActivityPub diseñado para el autohospedaje sencillo de algunas personas en sistemas de bajo consumo de energía, como computadoras de placa única o laptops antiguas. + +Ejecute su propia presencia en las redes sociales de la forma que desee y despídase de las grandes tecnologías. + +Ahora, vayamos ... diff --git a/defaultwelcome/welcome_fr.md b/defaultwelcome/welcome_fr.md new file mode 100644 index 000000000..9fd72437e --- /dev/null +++ b/defaultwelcome/welcome_fr.md @@ -0,0 +1,6 @@ +### Bienvenue à INSTANCE +Il s'agit d'un serveur ActivityPub conçu pour l'auto-hébergement facile de quelques personnes sur des systèmes à faible consommation d'énergie, tels que des ordinateurs monocarte ou d'anciens ordinateurs portables. + +Gérez votre propre présence sur les réseaux sociaux comme vous le souhaitez et dites au revoir à Big Tech. + +Maintenant, allons-y ... diff --git a/defaultwelcome/welcome_ga.md b/defaultwelcome/welcome_ga.md new file mode 100644 index 000000000..c9a11c680 --- /dev/null +++ b/defaultwelcome/welcome_ga.md @@ -0,0 +1,6 @@ +### Fáilte go INSTANCE +Is freastalaí ActivityPub é seo atá deartha chun féin-óstáil éasca a dhéanamh ar chúpla duine ar chórais ísealchumhachta, mar ríomhairí boird aonair nó sean ríomhairí glúine. + +Rith do láithreacht líonra sóisialta féin ar an mbealach is mian leat, agus slán a fhágáil le Big Tech. + +Anois, ligeann duit dul ... diff --git a/defaultwelcome/welcome_hi.md b/defaultwelcome/welcome_hi.md new file mode 100644 index 000000000..13923d095 --- /dev/null +++ b/defaultwelcome/welcome_hi.md @@ -0,0 +1,6 @@ +### INSTANCE पर आपका स्वागत है +यह एक एक्टिविटीपब सर्वर है जो कम पावर सिस्टम पर सिंगल बोर्ड कंप्यूटर या पुराने लैपटॉप जैसे कुछ लोगों की आसान सेल्फ-होस्टिंग के लिए बनाया गया है। + +जिस तरह से आप चाहते हैं, अपने खुद के सोशल नेटवर्क उपस्थिति को चलाएं और बिग टेक को अलविदा कहें। + +अब, चल रहा है ... diff --git a/defaultwelcome/welcome_it.md b/defaultwelcome/welcome_it.md new file mode 100644 index 000000000..498caf115 --- /dev/null +++ b/defaultwelcome/welcome_it.md @@ -0,0 +1,6 @@ +### Benvenuto in INSTANCE +Questo è un server ActivityPub progettato per un facile self-hosting di poche persone su sistemi a basso consumo, come computer a scheda singola o vecchi laptop. + +Gestisci la tua presenza sui social network come preferisci e saluta Big Tech. + +Ora andiamo ... diff --git a/defaultwelcome/welcome_ja.md b/defaultwelcome/welcome_ja.md new file mode 100644 index 000000000..7e21a1821 --- /dev/null +++ b/defaultwelcome/welcome_ja.md @@ -0,0 +1,6 @@ +### INSTANCEへようこそ +これは、シングルボードコンピューターや古いラップトップなどの低電力システムで数人を簡単にセルフホスティングするために設計されたActivityPubサーバーです。 + +独自のソーシャルネットワークプレゼンスを希望どおりに実行し、BigTechに別れを告げます。 + +さあ、始めましょう... diff --git a/defaultwelcome/welcome_oc.md b/defaultwelcome/welcome_oc.md new file mode 100644 index 000000000..2a90b3a52 --- /dev/null +++ b/defaultwelcome/welcome_oc.md @@ -0,0 +1,6 @@ +# Welcome +Epicyon is an ActivityPub server designed for easy self-hosting of a few people on low power systems, such as single board computers or old laptops. + +Run your own social network presence the way you want to, and say goodbye to Big Tech. + +Now, lets get going... diff --git a/defaultwelcome/welcome_pt.md b/defaultwelcome/welcome_pt.md new file mode 100644 index 000000000..f302f5aec --- /dev/null +++ b/defaultwelcome/welcome_pt.md @@ -0,0 +1,6 @@ +# Bem-vindo a INSTANCE +Este é um servidor ActivityPub projetado para fácil auto-hospedagem de algumas pessoas em sistemas de baixo consumo de energia, como computadores de placa única ou laptops antigos. + +Administre sua própria presença na rede social do jeito que você quiser e diga adeus à Big Tech. + +Agora, vamos indo ... diff --git a/defaultwelcome/welcome_ru.md b/defaultwelcome/welcome_ru.md new file mode 100644 index 000000000..65c82400d --- /dev/null +++ b/defaultwelcome/welcome_ru.md @@ -0,0 +1,6 @@ +### Добро пожаловать в INSTANCE +Это сервер ActivityPub, предназначенный для простого самостоятельного размещения нескольких человек в системах с низким энергопотреблением, таких как одноплатные компьютеры или старые ноутбуки. + +Управляйте своим присутствием в социальных сетях так, как вы хотите, и попрощайтесь с Big Tech. + +А теперь поехали ... diff --git a/defaultwelcome/welcome_zh.md b/defaultwelcome/welcome_zh.md new file mode 100644 index 000000000..978734e94 --- /dev/null +++ b/defaultwelcome/welcome_zh.md @@ -0,0 +1,6 @@ +### 欢迎来到INSTANCE +这是一个ActivityPub服务器,设计用于在低功耗系统(例如单板计算机或旧笔记本电脑)上轻松实现一些人的自我托管。 + +随心所欲地经营自己的社交网络,并与Big Tech道别。 + +现在,开始吧... diff --git a/epicyon-profile.css b/epicyon-profile.css index 2afefdc66..384c60893 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -599,15 +599,15 @@ a:focus { vertical-align: middle; } -.darker { +.container.darker { background-color: var(--main-bg-color-reply); } -.dm { +.container.dm { background-color: var(--main-bg-color-dm); } -.report { +.container.report { border-color: #255; background-color: var(--main-bg-color-report); } diff --git a/epicyon-welcome.css b/epicyon-welcome.css new file mode 100644 index 000000000..21a2ec8a1 --- /dev/null +++ b/epicyon-welcome.css @@ -0,0 +1,239 @@ +@chaste "UTF-8"; + +:root { + --welcome-bg-color: #282c37; + --link-bg-color: #282c37; + --welcome-fg-color: #dddddd; + --main-link-color: #999; + --main-visited-color: #888; + --border-color: #505050; + --border-width: 2px; + --font-size-header: 18px; + --font-color-header: #ccc; + --welcome-font-size: 22px; + --welcome-font-size-mobile: 40px; + --text-entry-foreground: #ccc; + --text-entry-background: #111; + --time-color: #aaa; + --welcome-button-width: 12ch; + --button-text: #FFFFFF; + --button-background: #999; + --button-selected: #666; + --form-border-radius: 30px; + --focus-color: white; + --line-spacing: 130%; + --welcome-logo-width: 20%; + --welcome-avatar-width: 40%; + --main-link-color-hover: #bbb; + --rendering: normal; +} + +@font-face { + font-family: 'Bedstead'; + font-style: italic; + font-weight: normal; + font-display: block; + src: url('./fonts/bedstead.otf') format('opentype'); +} +@font-face { + font-family: 'Bedstead'; + font-style: normal; + font-weight: normal; + font-display: block; + src: url('./fonts/bedstead.otf') format('opentype'); +} + +body, html { + background-color: var(--welcome-bg-color); + color: var(--welcome-fg-color); + + background-image: url("/welcome-background.jpg"); + background-size: cover; + -webkit-background-size: cover; + -moz-background-size: cover; + background-repeat: no-repeat; + background-position: center; + height: 100%; + font-family: Arial, Helvetica, sans-serif; + max-width: 60%; + min-width: 600px; + margin: 0 auto; + font-size: var(--welcome-font-size); + line-height: var(--line-spacing); + image-rendering: var(--rendering); +} + +a, u { + color: var(--welcome-fg-color); +} + +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 { + color: var(--main-link-color-hover); +} + +a:visited:hover { + color: var(--main-link-color-hover); +} + +a:focus { + border: 2px solid var(--focus-color); +} + +form { + border: var(--border-width) solid var(--border-color); + border-radius: var(--form-border-radius); +} + +.transparent { + color: transparent; + background: transparent; + font-size: 0px; + line-height: 0px; + height: 0px; +} + +button { + background-color: var(--button-background); + color: var(--button-text); + padding: 14px 20px; + margin: 8px 0; + border: none; + cursor: pointer; + width: var(--welcome-button-width); + font-size: var(--welcome-font-size); + font-family: Arial, Helvetica, sans-serif; +} + +.welcome-text { + font-size: var(--welcome-font-size); + font-family: Arial, Helvetica, sans-serif; +} + +button:hover { + opacity: 0.8; +} + +.imgcontainer { + text-align: center; + margin: 24px 0 12px 0; +} + +.imgcontainer img { + width: var(--welcome-logo-width); +} + +img.avatar { + width: 40%; + border-radius: 50%; +} + +.container { + padding: 16px; +} + +.container img.welcomeavatar { + width: var(--welcome-avatar-width); +} + +.container.next { + float: right; +} + +span.psw { + float: right; + padding-top: 16px; +} + +@media screen and (min-width: 400px) { + body, html { + background-color: var(--welcome-bg-color); + color: var(--welcome-fg-color); + height: 100%; + font-family: Arial, Helvetica, sans-serif; + max-width: 60%; + min-width: 600px; + margin: 0 auto; + font-size: var(--welcome-font-size); + font-family: Arial, Helvetica, sans-serif; + position: relative; + } + .welcome-text { + font-size: var(--welcome-font-size); + font-family: Arial, Helvetica, sans-serif; + } + input[type=text], input[type=password], textarea { + width: 100%; + padding: 12px 20px; + margin: 8px 0; + display: inline-block; + border: 1px solid #ccc; + box-sizing: border-box; + font-size: var(--welcome-font-size); + font-family: Arial, Helvetica, sans-serif; + } + button { + background-color: var(--button-background); + color: var(--button-text); + padding: 14px 20px; + margin: 8px 0; + border: none; + cursor: pointer; + width: var(--welcome-button-width); + font-size: var(--welcome-font-size); + font-family: Arial, Helvetica, sans-serif; + } +} + +@media screen and (max-width: 1000px) { + body, html { + background-color: var(--welcome-bg-color); + color: var(--welcome-fg-color); + height: 100%; + font-family: Arial, Helvetica, sans-serif; + max-width: 95%; + min-width: 600px; + margin: 0 auto; + font-size: var(--welcome-font-size-mobile); + font-family: Arial, Helvetica, sans-serif; + position: relative; + } + .welcome-text { + font-size: var(--welcome-font-size-mobile); + font-family: Arial, Helvetica, sans-serif; + } + input[type=text], input[type=password], textarea { + width: 100%; + padding: 12px 20px; + margin: 8px 0; + display: inline-block; + border: 1px solid #ccc; + box-sizing: border-box; + font-size: var(--welcome-font-size-mobile); + font-family: Arial, Helvetica, sans-serif; + } + button { + background-color: var(--button-background); + color: var(--button-text); + padding: 14px 20px; + margin: 8px 0; + border: none; + cursor: pointer; + width: var(--welcome-button-width); + font-size: var(--welcome-font-size-mobile); + font-family: Arial, Helvetica, sans-serif; + } +} diff --git a/epicyon.py b/epicyon.py index cf0289c65..5b5d01b8b 100644 --- a/epicyon.py +++ b/epicyon.py @@ -1617,6 +1617,13 @@ if args.addaccount: if not args.domain or not getConfigParam(baseDir, 'domain'): print('Use the --domain option to set the domain name') sys.exit() + + configuredDomain = getConfigParam(baseDir, 'domain') + if configuredDomain: + if domain != configuredDomain: + print('The account domain is expected to be ' + configuredDomain) + sys.exit() + if not validNickname(domain, nickname): print(nickname + ' is a reserved name. Use something different.') sys.exit() @@ -1688,6 +1695,13 @@ if args.rmaccount: if not args.domain or not getConfigParam(baseDir, 'domain'): print('Use the --domain option to set the domain name') sys.exit() + + configuredDomain = getConfigParam(baseDir, 'domain') + if configuredDomain: + if domain != configuredDomain: + print('The account domain is expected to be ' + configuredDomain) + sys.exit() + if args.deactivate: if deactivateAccount(baseDir, nickname, domain): print('Account for ' + nickname + '@' + domain + diff --git a/follow.py b/follow.py index cce18f1b2..c3a383664 100644 --- a/follow.py +++ b/follow.py @@ -126,6 +126,7 @@ def _removeFromFollowRejects(baseDir: str, def isFollowingActor(baseDir: str, nickname: str, domain: str, actor: str) -> bool: """Is the given nickname following the given actor? + The actor can also be a handle: nickname@domain """ if ':' in domain: domain = domain.split(':')[0] diff --git a/inbox.py b/inbox.py index 86507b87d..0efca270d 100644 --- a/inbox.py +++ b/inbox.py @@ -40,6 +40,7 @@ from categories import setHashtagCategory from httpsig import verifyPostHeaders from session import createSession from session import getJson +from follow import isFollowingActor from follow import receiveFollowRequest from follow import getFollowersOfActor from follow import unfollowerOfAccount @@ -57,6 +58,7 @@ from utils import updateAnnounceCollection from utils import undoAnnounceCollectionEntry from utils import dangerousMarkup from httpsig import messageContentDigest +from posts import createDirectMessagePost from posts import validContentWarning from posts import downloadAnnounce from posts import isDM @@ -73,7 +75,6 @@ from git import receiveGitPatch from followingCalendar import receivingCalendarEvents from happening import saveEventPost from delete import removeOldHashtags -from follow import isFollowingActor from categories import guessHashtagCategory from context import hasValidContext @@ -2056,6 +2057,80 @@ def _updateLastSeen(baseDir: str, handle: str, actor: str) -> None: lastSeenFile.write(str(daysSinceEpoch)) +def _bounceDM(senderPostId: str, session, httpPrefix: str, + baseDir: str, nickname: str, domain: str, port: int, + sendingHandle: str, federationList: [], + sendThreads: [], postLog: [], + cachedWebfingers: {}, personCache: {}, + translate: {}, debug: bool, + lastBounceMessage: []) -> bool: + """Sends a bounce message back to the sending handle + if a DM has been rejected + """ + print(nickname + '@' + domain + + ' cannot receive DM from ' + sendingHandle + + ' because they do not follow them') + + # Don't send out bounce messages too frequently. + # Otherwise an adversary could try to DoS your instance + # by continuously sending DMs to you + currTime = int(time.time()) + if currTime - lastBounceMessage[0] < 60: + return False + + # record the last time that a bounce was generated + lastBounceMessage[0] = currTime + + senderNickname = sendingHandle.split('@')[0] + senderDomain = sendingHandle.split('@')[1] + senderPort = port + if ':' in senderDomain: + senderPortStr = senderDomain.split(':')[1] + if senderPortStr.isdigit(): + senderPort = int(senderPortStr) + senderDomain = senderDomain.split(':')[0] + cc = [] + + # create the bounce DM + subject = None + content = translate['DM bounce'] + followersOnly = False + saveToFile = False + clientToServer = False + commentsEnabled = False + attachImageFilename = None + mediaType = None + imageDescription = '' + inReplyTo = removeIdEnding(senderPostId) + inReplyToAtomUri = None + schedulePost = False + eventDate = None + eventTime = None + location = None + postJsonObject = \ + createDirectMessagePost(baseDir, nickname, domain, port, + httpPrefix, content, followersOnly, + saveToFile, clientToServer, + commentsEnabled, + attachImageFilename, mediaType, + imageDescription, + inReplyTo, inReplyToAtomUri, + subject, debug, schedulePost, + eventDate, eventTime, location) + if not postJsonObject: + print('WARN: unable to create bounce message to ' + sendingHandle) + return False + # bounce DM goes back to the sender + print('Sending bounce DM to ' + sendingHandle) + sendSignedJson(postJsonObject, session, baseDir, + nickname, domain, port, + senderNickname, senderDomain, senderPort, cc, + httpPrefix, False, False, federationList, + sendThreads, postLog, cachedWebfingers, + personCache, debug, __version__) + return True + + def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, session, keyId: str, handle: str, messageJson: {}, baseDir: str, httpPrefix: str, sendThreads: [], @@ -2070,7 +2145,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, unitTest: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, allowLocalNetworkAccess: bool, - peertubeInstances: []) -> bool: + peertubeInstances: [], + lastBounceMessage: []) -> bool: """ Anything which needs to be done after initial checks have passed """ actor = keyId @@ -2263,41 +2339,68 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, postIsDM = isDM(postJsonObject) if postIsDM: if nickname != 'inbox': + # check for the flag file which indicates to + # only receive DMs from people you are following followDMsFilename = \ baseDir + '/accounts/' + \ nickname + '@' + domain + '/.followDMs' if os.path.isfile(followDMsFilename): + # get the file containing following handles followingFilename = \ baseDir + '/accounts/' + \ nickname + '@' + domain + '/following.txt' + # who is sending a DM? if not postJsonObject.get('actor'): return False sendingActor = postJsonObject['actor'] sendingActorNickname = \ getNicknameFromActor(sendingActor) + if not sendingActorNickname: + return False sendingActorDomain, sendingActorPort = \ getDomainFromActor(sendingActor) - if sendingActorNickname and sendingActorDomain: - if not os.path.isfile(followingFilename): - print('No following.txt file exists for ' + - nickname + '@' + domain + - ' so not accepting DM from ' + - sendingActorNickname + '@' + - sendingActorDomain) - return False - sendH = \ - sendingActorNickname + '@' + sendingActorDomain - if sendH != nickname + '@' + domain: - if sendH not in \ - open(followingFilename).read(): - print(nickname + '@' + domain + - ' cannot receive DM from ' + - sendH + - ' because they do not ' + - 'follow them') - return False - else: + if not sendingActorDomain: return False + # check that the following file exists + if not os.path.isfile(followingFilename): + print('No following.txt file exists for ' + + nickname + '@' + domain + + ' so not accepting DM from ' + + sendingActorNickname + '@' + + sendingActorDomain) + return False + # get the handle of the DM sender + sendH = \ + sendingActorNickname + '@' + sendingActorDomain + # Not sending to yourself + if sendH != nickname + '@' + domain: + # check the follow + if not isFollowingActor(baseDir, + nickname, domain, + sendH): + # send back a bounce DM + if postJsonObject.get('id') and \ + postJsonObject.get('object'): + # don't send bounces back to + # replies to bounce messages + obj = postJsonObject['object'] + if isinstance(obj, dict): + if not obj.get('inReplyTo'): + senderPostId = \ + postJsonObject['id'] + _bounceDM(senderPostId, + session, httpPrefix, + baseDir, + nickname, domain, + port, sendH, + federationList, + sendThreads, postLog, + cachedWebfingers, + personCache, + translate, debug, + lastBounceMessage) + return False + # dm index will be updated updateIndexList.append('dm') _dmNotify(baseDir, handle, @@ -2513,6 +2616,11 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int, heartBeatCtr = 0 queueRestoreCtr = 0 + # time when the last DM bounce message was sent + # This is in a list so that it can be changed by reference + # within _bounceDM + lastBounceMessage = [int(time.time())] + while True: time.sleep(1) @@ -2969,7 +3077,8 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int, YTReplacementDomain, showPublishedDateOnly, allowLocalNetworkAccess, - peertubeInstances) + peertubeInstances, + lastBounceMessage) if debug: pprint(queueJson['post']) diff --git a/tests.py b/tests.py index 02fe2b604..ddab940d4 100644 --- a/tests.py +++ b/tests.py @@ -98,6 +98,7 @@ from newswire import parseFeedDate from mastoapiv1 import getMastoApiV1IdFromNickname from mastoapiv1 import getNicknameFromMastoApiV1Id from webapp_post import prepareHtmlPostNickname +from webapp_utils import markdownToHtml testServerAliceRunning = False testServerBobRunning = False @@ -3282,9 +3283,43 @@ def testValidHashTag(): assert not validHashTag('This=IsAlsoNotValid"') +def testMarkdownToHtml(): + print('testMarkdownToHtml') + markdown = 'This is just plain text' + assert markdownToHtml(markdown) == markdown + + markdown = 'This is **bold**' + assert markdownToHtml(markdown) == 'This is bold' + + markdown = 'This is *italic*' + assert markdownToHtml(markdown) == 'This is italic' + + markdown = 'This is _underlined_' + assert markdownToHtml(markdown) == 'This is