diff --git a/blog.py b/blog.py index 2ba055066..5123b4223 100644 --- a/blog.py +++ b/blog.py @@ -282,7 +282,7 @@ def _html_blog_post_content(debug: bool, session, authorized: bool, blog_str += '
' + attachment_str + '
' if json_content: content_str = add_embedded_elements(translate, json_content, - peertube_instances) + peertube_instances, domain_full) if post_json_object['object'].get('tag'): post_json_object_tags = post_json_object['object']['tag'] content_str = replace_emoji_from_tags(session, base_dir, diff --git a/daemon.py b/daemon.py index b5767c0d6..c0e0e7a74 100644 --- a/daemon.py +++ b/daemon.py @@ -178,6 +178,7 @@ from webapp_calendar import html_calendar_delete_confirm from webapp_calendar import html_calendar from webapp_about import html_about from webapp_specification import html_specification +from webapp_manual import html_manual from webapp_accesskeys import html_access_keys from webapp_accesskeys import load_access_keys_for_accounts from webapp_confirm import html_confirm_delete @@ -456,6 +457,7 @@ class PubServer(BaseHTTPRequestHandler): """Detect if a request contains a MiTM """ mitm_domains = ['cloudflare'] + # look for domains within these headers check_headers = ( 'Server', 'Report-To', 'Report-to', 'report-to', 'Expect-CT', 'Expect-Ct', 'expect-ct' @@ -464,16 +466,22 @@ class PubServer(BaseHTTPRequestHandler): for header_name in check_headers: if self.headers.get(header_name): if interloper in self.headers[header_name]: + print('MITM: ' + header_name + ' = ' + + self.headers[header_name]) return True - # The presence if these headers on their own indicates a MiTM + # The presence of these headers on their own indicates a MiTM mitm_headers = ( 'CF-Connecting-IP', 'CF-RAY', 'CF-IPCountry', 'CF-Visitor', 'CDN-Loop', 'CF-Worker', 'CF-Cache-Status' ) for header_name in mitm_headers: if self.headers.get(header_name): + print('MITM: ' + header_name + ' = ' + + self.headers[header_name]) return True if self.headers.get(header_name.lower()): + print('MITM: ' + header_name + ' = ' + + self.headers[header_name.lower()]) return True return False @@ -16466,6 +16474,36 @@ class PubServer(BaseHTTPRequestHandler): self.server.debug) return + if self.path in ('/manual', '/usermanual', '/userguide'): + if calling_domain.endswith('.onion'): + msg = \ + html_manual(self.server.base_dir, 'http', + self.server.onion_domain, + None, self.server.translate, + self.server.system_language) + elif calling_domain.endswith('.i2p'): + msg = \ + html_manual(self.server.base_dir, 'http', + self.server.i2p_domain, + None, self.server.translate, + self.server.system_language) + else: + msg = \ + html_manual(self.server.base_dir, + self.server.http_prefix, + self.server.domain_full, + self.server.onion_domain, + self.server.translate, + self.server.system_language) + msg = msg.encode('utf-8') + msglen = len(msg) + self._login_headers('text/html', msglen, calling_domain) + self._write(msg) + fitness_performance(getreq_start_time, self.server.fitness, + '_GET', 'show user manual screen', + self.server.debug) + return + if html_getreq and users_in_path and authorized and \ self.path.endswith('/accesskeys'): nickname = self.path.split('/users/')[1] diff --git a/epicyon-profile.css b/epicyon-profile.css index 1d7c44c58..8b3723655 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -361,6 +361,11 @@ blockquote { font-size: var(--quote-font-size); quotes: "\201C""\201D""\2018""\2019"; } + +.tiktok-embed { + quotes: ""; +} + blockquote:before { content: open-quote; font-size: 2em; diff --git a/filters.py b/filters.py index 4a22ab164..6bdc4d364 100644 --- a/filters.py +++ b/filters.py @@ -13,6 +13,7 @@ from utils import text_in_file from utils import remove_eol from utils import standardize_text from utils import remove_inverted_text +from utils import remove_square_capitals def add_filter(base_dir: str, nickname: str, domain: str, words: str) -> bool: @@ -125,6 +126,7 @@ def _is_filtered_base(filename: str, content: str, return False content = remove_inverted_text(content, system_language) + content = remove_square_capitals(content, system_language) # convert any fancy characters to ordinary ones content = standardize_text(content) diff --git a/inbox.py b/inbox.py index 309c65d34..4530aec6c 100644 --- a/inbox.py +++ b/inbox.py @@ -742,23 +742,23 @@ def save_post_to_inbox_queue(base_dir: str, http_prefix: str, print('DIGEST|' + time_diff_str + '|' + filename) new_queue_item = { - 'originalId': original_post_id, - 'id': post_id, - 'actor': actor, - 'nickname': nickname, - 'domain': domain, - 'postNickname': post_nickname, - 'postDomain': post_domain, - 'sharedInbox': shared_inbox_item, - 'published': published, - 'httpHeaders': http_headers, - 'path': post_path, - 'post': post_json_object, - 'original': original_post_json_object, - 'digest': digest, - 'filename': filename, - 'destination': destination, - 'mitm': mitm + "originalId": original_post_id, + "id": post_id, + "actor": actor, + "nickname": nickname, + "domain": domain, + "postNickname": post_nickname, + "postDomain": post_domain, + "sharedInbox": shared_inbox_item, + "published": published, + "httpHeaders": http_headers, + "path": post_path, + "post": post_json_object, + "original": original_post_json_object, + "digest": digest, + "filename": filename, + "destination": destination, + "mitm": mitm } if debug: @@ -2410,7 +2410,7 @@ def _receive_announce(recent_posts_cache: {}, peertube_instances: [], max_like_count: int, cw_lists: {}, lists_enabled: str, bold_reading: bool, - dogwhistles: {}) -> bool: + dogwhistles: {}, mitm: bool) -> bool: """Receives an announce activity within the POST section of HTTPServer """ if message_json['type'] != 'Announce': @@ -2510,9 +2510,17 @@ def _receive_announce(recent_posts_cache: {}, if debug: print('Generating html for announce ' + message_json['id']) timezone = get_account_timezone(base_dir, nickname, domain) - mitm = False - if os.path.isfile(post_filename.replace('.json', '') + '.mitm'): - mitm = True + + if mitm: + post_filename_mitm = \ + post_filename.replace('.json', '') + '.mitm' + try: + with open(post_filename_mitm, 'w+', + encoding='utf-8') as mitm_file: + mitm_file.write('\n') + except OSError: + print('EX: unable to write mitm ' + post_filename_mitm) + announce_html = \ individual_post_as_html(signing_priv_key_pem, True, recent_posts_cache, max_recent_posts, @@ -4152,7 +4160,7 @@ def _inbox_after_initial(server, inbox_start_time, allow_deletion, peertube_instances, max_like_count, cw_lists, lists_enabled, - bold_reading, dogwhistles): + bold_reading, dogwhistles, mitm): if debug: print('DEBUG: Announce accepted from ' + actor) fitness_performance(inbox_start_time, server.fitness, diff --git a/manual/back/css/style.css b/manual/back/css/style.css new file mode 100644 index 000000000..45e909c02 --- /dev/null +++ b/manual/back/css/style.css @@ -0,0 +1,203 @@ +/* ubuntu-condensed-regular - latin */ +@font-face { + font-family: 'Ubuntu Condensed'; + font-style: normal; + font-weight: 400; + src: url('../fonts/ubuntu-condensed-v11-latin-regular.eot'); /* IE9 Compat Modes */ + src: local(''), + url('../fonts/ubuntu-condensed-v11-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/ubuntu-condensed-v11-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/ubuntu-condensed-v11-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/ubuntu-condensed-v11-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/ubuntu-condensed-v11-latin-regular.svg#UbuntuCondensed') format('svg'); /* Legacy iOS */ +} + +*{ + box-sizing: border-box; +} + +body{ + margin: 0; +} + +#container{ + width: 800px; + margin: 0 auto; + padding: 40px 0; + background: linear-gradient(90deg, #FFFFFF 80%, #a1a2b6 80%); +} + +main{ + width: 60%; + float: left; +} + +#main-header h3{ + margin-top: 0; + font-size: 0.9em; + font-weight: 100; + font-family: "Trebuchet MS", Helvetica, sans-serif; +} + +#article-header{ + font-family: 'Ubuntu Condensed', sans-serif; + text-align: center; +} + + #article-header h1{ + margin: 0; + font-size: 2.5em; + color: #8b2928; + } + + #article-header h6{ + margin: 2px 0 0 0; + font-weight: 600; + font-size: 1em; + } + +#intro p{ + font-size: 1.1em; + line-height: 1.2em; + font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif; +} + + #intro p:first-child:first-letter{ + font-family: 'Ubuntu Condensed', sans-serif; + font-size: 4.5em; + float: left; + line-height: 0.8em; + margin-right: 8px; + color: #908C6F; + } + + #intro #title{ + font-family: 'Ubuntu Condensed', sans-serif; + color: #908C6F; + font-weight: bold; + } + +#inside #section-header h3{ + font-family: 'Ubuntu Condensed', sans-serif; + color: #908C6F; + font-size: 1.3em; + font-weight: bold; + margin-bottom: 0; +} + +#inside ul{ + margin-top: 5px; + padding-left: 18px; + list-style: none; +} + +#inside ul li{ + font-size: 1.1em; + line-height: 1.4em; + text-indent: -1em; + font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif; +} + +#inside ul li:before{ + position: relative; + top: 2px; + font-size: 1.1em; + content: "• "; + color: #8b2928; +} + +#inside p{ + font-size: 1.1em; + line-height: 1.4em; + font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif; +} + +#author{ + font-size: 1.1em; + line-height: 1.4em; + font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif; + margin-bottom: 0; +} + + #author #author-name{ + font-family: 'Ubuntu Condensed', sans-serif; + color: #908C6F; + font-weight: bold; + } + +aside{ + width: 40%; + float: left; + padding: 0 35px 0 20px; +} + +aside #quotes{ + background: #bbc3cc; + background: -moz-linear-gradient(top, #bbc3cc 0%, #bbc3cc 11%, #cedae7 49%, #e0ebf7 76%, #ffffff 100%); + background: -webkit-gradient(left top, left bottom, color-stop(0%, #bbc3cc), color-stop(11%, #bbc3cc), color-stop(49%, #cedae7), color-stop(76%, #e0ebf7), color-stop(100%, #ffffff)); + background: -webkit-linear-gradient(top, #bbc3cc 0%, #bbc3cc 11%, #cedae7 49%, #e0ebf7 76%, #ffffff 100%); + background: -o-linear-gradient(top, #bbc3cc 0%, #bbc3cc 11%, #cedae7 49%, #e0ebf7 76%, #ffffff 100%); + background: -ms-linear-gradient(top, #bbc3cc 0%, #bbc3cc 11%, #cedae7 49%, #e0ebf7 76%, #ffffff 100%); + background: linear-gradient(to bottom, #bbc3cc 0%, #bbc3cc 11%, #cedae7 49%, #e0ebf7 76%, #ffffff 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#c9bd71', endColorstr='#ffffff', GradientType=0 ); + padding: 10px 10px 5px 10px; +} + +aside p{ + text-align: center; + font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif; +} + +aside .quote{ + font-size: 1.2em; + margin-bottom: 0; +} + +aside .quote:before, aside .quote:after{ + content: '"'; + color: #8b2928; + font-weight: bold; + font-size: 1.2em; +} + +aside .author{ + font-size: 0.9em; + margin-top: 5px; +} + +#free-ebook img{ + display: block; + width: 200px; + margin: 0 auto; +} + +#bar-code img{ + display: block; + width: 200px; + margin: 0 auto; + margin-top: 50px; +} + +#page-footer{ + clear: both; + background: url("../img/barcode.gif") no-repeat 530px bottom; +} + +#page-footer #instructions{ + width: 60%; + padding-top: 15px; + font-size: 0.8em; + font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif; +} + +#page-footer #price{ + display: inline; + margin-left: 55px; + font-size: 0.8em; + font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif; +} + +#page-footer img{ + padding-top: 50px; + width: 150px; +} diff --git a/manual/back/fonts/ubuntu-condensed-v11-latin-regular.eot b/manual/back/fonts/ubuntu-condensed-v11-latin-regular.eot new file mode 100644 index 000000000..2c6ebe0c6 Binary files /dev/null and b/manual/back/fonts/ubuntu-condensed-v11-latin-regular.eot differ diff --git a/manual/back/fonts/ubuntu-condensed-v11-latin-regular.svg b/manual/back/fonts/ubuntu-condensed-v11-latin-regular.svg new file mode 100644 index 000000000..ac471d595 --- /dev/null +++ b/manual/back/fonts/ubuntu-condensed-v11-latin-regular.svg @@ -0,0 +1,351 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/manual/back/fonts/ubuntu-condensed-v11-latin-regular.ttf b/manual/back/fonts/ubuntu-condensed-v11-latin-regular.ttf new file mode 100644 index 000000000..a8e36bee3 Binary files /dev/null and b/manual/back/fonts/ubuntu-condensed-v11-latin-regular.ttf differ diff --git a/manual/back/fonts/ubuntu-condensed-v11-latin-regular.woff b/manual/back/fonts/ubuntu-condensed-v11-latin-regular.woff new file mode 100644 index 000000000..369f738b6 Binary files /dev/null and b/manual/back/fonts/ubuntu-condensed-v11-latin-regular.woff differ diff --git a/manual/back/fonts/ubuntu-condensed-v11-latin-regular.woff2 b/manual/back/fonts/ubuntu-condensed-v11-latin-regular.woff2 new file mode 100644 index 000000000..ce5cedc36 Binary files /dev/null and b/manual/back/fonts/ubuntu-condensed-v11-latin-regular.woff2 differ diff --git a/manual/back/img/barcode.gif b/manual/back/img/barcode.gif new file mode 100644 index 000000000..5c3af06e8 Binary files /dev/null and b/manual/back/img/barcode.gif differ diff --git a/manual/back/img/ebooks.png b/manual/back/img/ebooks.png new file mode 100644 index 000000000..7b8ad8912 Binary files /dev/null and b/manual/back/img/ebooks.png differ diff --git a/manual/back/img/logo.gif b/manual/back/img/logo.gif new file mode 100644 index 000000000..2ff13fd21 Binary files /dev/null and b/manual/back/img/logo.gif differ diff --git a/manual/back/index.html b/manual/back/index.html new file mode 100644 index 000000000..60166af65 --- /dev/null +++ b/manual/back/index.html @@ -0,0 +1,126 @@ + + + + + JavaScript + + + + + +
+ +
+ +
+

INTERNET

+
+ +
+ +
+

EPICYON

+
ActivityPub server for the Small Web
+
+ +
+

+ Do you want to run a fediverse instance on a small computer or laptop? + Hate websites with poor accessibility bloated with insecure javascript? + Want to keep things simple, small and low maintenance? + If so, then the Epicyon ActivityPub server is for you. +

+

+ The Epicyon user manual + introduces you to the basics of how to install and administer a + fediverse instance, avoiding the pitfalls and gaining the advantages + of having your own social presence on the open web. +

+
+ +
+ +
+

What's Inside

+
+ +
    +
  • Installation and configuration
  • +
  • User profiles and timelines
  • +
  • Customisation and moderation
  • +
  • The sharing economy
  • +
  • Building web communities
  • +
+ +

This book assumes readers understand the basics of Linux system administration.

+ +
+ +
+ +

+ Bob Mottram is a free software developer with a + focus on federated, autonomous and self-hosted server systems. He maintains + a blog at blog.libreserver.org. +

+ +
+ +
+ +
+ + + + + +
+ + + diff --git a/manual/cover/all.js b/manual/cover/all.js new file mode 100644 index 000000000..f19659120 --- /dev/null +++ b/manual/cover/all.js @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.0.11 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +!function(){"use strict";var c={};try{"undefined"!=typeof window&&(c=window)}catch(c){}var l=(c.navigator||{}).userAgent,h=void 0===l?"":l,v=c,z=(~h.indexOf("MSIE")||h.indexOf("Trident/"),"___FONT_AWESOME___"),e=function(){try{return!0}catch(c){return!1}}(),m=[1,2,3,4,5,6,7,8,9,10],a=m.concat([11,12,13,14,15,16,17,18,19,20]);["xs","sm","lg","fw","ul","li","border","pull-left","pull-right","spin","pulse","rotate-90","rotate-180","rotate-270","flip-horizontal","flip-vertical","stack","stack-1x","stack-2x","inverse","layers","layers-text","layers-counter"].concat(m.map(function(c){return c+"x"})).concat(a.map(function(c){return"w-"+c}));var s=v||{};s[z]||(s[z]={}),s[z].styles||(s[z].styles={}),s[z].hooks||(s[z].hooks={}),s[z].shims||(s[z].shims=[]);var t=s[z],f=Object.assign||function(c){for(var l=1;l1&&void 0!==arguments[1]?arguments[1]:{}).asNewDefault,h=void 0!==l&&l,v=Object.keys(O),z=h?function(c){return~v.indexOf(c)&&!~A.indexOf(c)}:function(c){return~v.indexOf(c)};Object.keys(c).forEach(function(l){z(l)&&(O[l]=c[l])})}a.FontAwesomeConfig=O;var N=a||{};N[n]||(N[n]={}),N[n].styles||(N[n].styles={}),N[n].hooks||(N[n].hooks={}),N[n].shims||(N[n].shims=[]);var E=N[n],P=[],_=!1;M&&((_=(s.documentElement.doScroll?/^loaded|^c/:/^loaded|^i|^c/).test(s.readyState))||s.addEventListener("DOMContentLoaded",function c(){s.removeEventListener("DOMContentLoaded",c),_=1,P.map(function(c){return c()})}));var T=function(c){M&&(_?setTimeout(c,0):P.push(c))},F=H,I={size:16,x:0,y:0,rotate:0,flipX:!1,flipY:!1};function R(c){if(c&&M){var l=s.createElement("style");l.setAttribute("type","text/css"),l.innerHTML=c;for(var h=s.head.childNodes,v=null,z=h.length-1;z>-1;z--){var e=h[z],m=(e.tagName||"").toUpperCase();["STYLE","LINK"].indexOf(m)>-1&&(v=e)}return s.head.insertBefore(l,v),c}}var W=0;function B(){return++W}function D(c){for(var l=[],h=(c||[]).length>>>0;h--;)l[h]=c[h];return l}function X(c){return c.classList?D(c.classList):(c.getAttribute("class")||"").split(" ").filter(function(c){return c})}function Y(c,l){var h,v=l.split("-"),z=v[0],e=v.slice(1).join("-");return z!==c||""===e||(h=e,~g.indexOf(h))?null:e}function U(c){return(""+c).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}function K(c){return Object.keys(c||{}).reduce(function(l,h){return l+(h+": ")+c[h]+";"},"")}function G(c){return c.size!==I.size||c.x!==I.x||c.y!==I.y||c.rotate!==I.rotate||c.flipX||c.flipY}function J(c){var l=c.transform,h=c.containerWidth,v=c.iconWidth;return{outer:{transform:"translate("+h/2+" 256)"},inner:{transform:"translate("+32*l.x+", "+32*l.y+") "+" "+("scale("+l.size/16*(l.flipX?-1:1)+", "+l.size/16*(l.flipY?-1:1)+") ")+" "+("rotate("+l.rotate+" 0 0)")},path:{transform:"translate("+v/2*-1+" -256)"}}}var Q={x:0,y:0,width:"100%",height:"100%"},Z=function(c){var l=c.children,h=c.attributes,v=c.main,z=c.mask,e=c.transform,m=v.width,a=v.icon,s=z.width,t=z.icon,f=J({transform:e,containerWidth:s,iconWidth:m}),r={tag:"rect",attributes:S({},Q,{fill:"white"})},M={tag:"g",attributes:S({},f.inner),children:[{tag:"path",attributes:S({},a.attributes,f.path,{fill:"black"})}]},i={tag:"g",attributes:S({},f.outer),children:[M]},n="mask-"+B(),H="clip-"+B(),V={tag:"defs",children:[{tag:"clipPath",attributes:{id:H},children:[t]},{tag:"mask",attributes:S({},Q,{id:n,maskUnits:"userSpaceOnUse",maskContentUnits:"userSpaceOnUse"}),children:[r,i]}]};return l.push(V,{tag:"rect",attributes:S({fill:"currentColor","clip-path":"url(#"+H+")",mask:"url(#"+n+")"},Q)}),{children:l,attributes:h}},$=function(c){var l=c.children,h=c.attributes,v=c.main,z=c.transform,e=K(c.styles);if(e.length>0&&(h.style=e),G(z)){var m=J({transform:z,containerWidth:v.width,iconWidth:v.width});l.push({tag:"g",attributes:S({},m.outer),children:[{tag:"g",attributes:S({},m.inner),children:[{tag:v.icon.tag,children:v.icon.children,attributes:S({},v.icon.attributes,m.path)}]}]})}else l.push(v.icon);return{children:l,attributes:h}},cc=function(c){var l=c.children,h=c.main,v=c.mask,z=c.attributes,e=c.styles,m=c.transform;if(G(m)&&h.found&&!v.found){var a=h.width/h.height/2,s=.5;z.style=K(S({},e,{"transform-origin":a+m.x/16+"em "+(s+m.y/16)+"em"}))}return[{tag:"svg",attributes:z,children:l}]},lc=function(c){var l=c.prefix,h=c.iconName,v=c.children,z=c.attributes,e=c.symbol,m=!0===e?l+"-"+O.familyPrefix+"-"+h:e;return[{tag:"svg",attributes:{style:"display: none;"},children:[{tag:"symbol",attributes:S({},z,{id:m}),children:v}]}]};function hc(c){var l=c.icons,h=l.main,v=l.mask,z=c.prefix,e=c.iconName,m=c.transform,a=c.symbol,s=c.title,t=c.extra,f=c.watchable,r=void 0!==f&&f,M=v.found?v:h,i=M.width,n=M.height,H="fa-w-"+Math.ceil(i/n*16),V=[O.replacementClass,e?O.familyPrefix+"-"+e:"",H].concat(t.classes).join(" "),C={children:[],attributes:S({},t.attributes,{"data-prefix":z,"data-icon":e,class:V,role:"img",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 "+i+" "+n})};r&&(C.attributes[o]=""),s&&C.children.push({tag:"title",attributes:{id:C.attributes["aria-labelledby"]||"title-"+B()},children:[s]});var L=S({},C,{prefix:z,iconName:e,main:h,mask:v,transform:m,symbol:a,styles:t.styles}),u=v.found&&h.found?Z(L):$(L),d=u.children,p=u.attributes;return L.children=d,L.attributes=p,a?lc(L):cc(L)}function vc(c){var l=c.content,h=c.width,v=c.height,z=c.transform,e=c.title,m=c.extra,a=c.watchable,s=void 0!==a&&a,t=S({},m.attributes,e?{title:e}:{},{class:m.classes.join(" ")});s&&(t[o]="");var f,r,M,n,V,C,L,u,d,p=S({},m.styles);G(z)&&(p.transform=(r=(f={transform:z,startCentered:!0,width:h,height:v}).transform,M=f.width,n=void 0===M?H:M,V=f.height,C=void 0===V?H:V,L=f.startCentered,d="",d+=(u=void 0!==L&&L)&&i?"translate("+(r.x/F-n/2)+"em, "+(r.y/F-C/2)+"em) ":u?"translate(calc(-50% + "+r.x/F+"em), calc(-50% + "+r.y/F+"em)) ":"translate("+r.x/F+"em, "+r.y/F+"em) ",d+="scale("+r.size/F*(r.flipX?-1:1)+", "+r.size/F*(r.flipY?-1:1)+") ",d+="rotate("+r.rotate+"deg) "),p["-webkit-transform"]=p.transform);var b=K(p);b.length>0&&(t.style=b);var g=[];return g.push({tag:"span",attributes:t,children:[l]}),e&&g.push({tag:"span",attributes:{class:"sr-only"},children:[e]}),g}var zc=function(){},ec=O.measurePerformance&&f&&f.mark&&f.measure?f:{mark:zc,measure:zc},mc='FA "5.0.11"',ac=function(c){ec.mark(mc+" "+c+" ends"),ec.measure(mc+" "+c,mc+" "+c+" begins",mc+" "+c+" ends")},sc={begin:function(c){return ec.mark(mc+" "+c+" begins"),function(){return ac(c)}},end:ac},tc=function(c,l,h,v){var z,e,m,a,s,t=Object.keys(c),f=t.length,r=void 0!==v?(a=l,s=v,function(c,l,h,v){return a.call(s,c,l,h,v)}):l;for(void 0===h?(z=1,m=c[t[0]]):(z=0,m=h);z"+m.map(uc).join("")+""}var dc=function(){};function pc(c){return"string"==typeof(c.getAttribute?c.getAttribute(o):null)}var bc={replace:function(c){var l=c[0],h=c[1].map(function(c){return uc(c)}).join("\n");if(l.parentNode&&l.outerHTML)l.outerHTML=h+(O.keepOriginalSource&&"svg"!==l.tagName.toLowerCase()?"\x3c!-- "+l.outerHTML+" --\x3e":"");else if(l.parentNode){var v=document.createElement("span");l.parentNode.replaceChild(v,l),v.outerHTML=h}},nest:function(c){var l=c[0],h=c[1];if(~X(l).indexOf(O.replacementClass))return bc.replace(c);var v=new RegExp(O.familyPrefix+"-.*");delete h[0].attributes.style;var z=h[0].attributes.class.split(" ").reduce(function(c,l){return l===O.replacementClass||l.match(v)?c.toSvg.push(l):c.toNode.push(l),c},{toNode:[],toSvg:[]});h[0].attributes.class=z.toSvg.join(" ");var e=h.map(function(c){return uc(c)}).join("\n");l.setAttribute("class",z.toNode.join(" ")),l.setAttribute(o,""),l.innerHTML=e}};function gc(c,l){var h="function"==typeof l?l:dc;0===c.length?h():(a.requestAnimationFrame||function(c){return c()})(function(){var l=!0===O.autoReplaceSvg?bc.replace:bc[O.autoReplaceSvg]||bc.replace,v=sc.begin("mutate");c.map(l),v(),h()})}var yc=!1;var wc=null;var Sc=function(c){var l=c.getAttribute("style"),h=[];return l&&(h=l.split(";").reduce(function(c,l){var h=l.split(":"),v=h[0],z=h.slice(1);return v&&z.length>0&&(c[v]=z.join(":").trim()),c},{})),h};var kc=function(c){var l,h,v,z,e=c.getAttribute("data-prefix"),m=c.getAttribute("data-icon"),a=void 0!==c.innerText?c.innerText.trim():"",s=Cc(X(c));return e&&m&&(s.prefix=e,s.iconName=m),s.prefix&&a.length>1?s.iconName=(v=s.prefix,z=c.innerText,ic[v][z]):s.prefix&&1===a.length&&(s.iconName=(l=s.prefix,h=function(c){for(var l="",h=0;h-1&&Yc(z.nextSibling),Yc(z),z=null),v&&!z){var e=h.getPropertyValue("content"),m=s.createElement("i");m.setAttribute("class",""+Bc[v[1]]),m.setAttribute(C,l),m.innerText=3===e.length?e.substr(1,1):e,":before"===l?c.insertBefore(m,c.firstChild):c.appendChild(m)}})})}(),yc=!1,l()}}function Kc(c){var l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(M){var h=s.documentElement.classList,v=function(c){return h.add(L+"-"+c)},z=function(c){return h.remove(L+"-"+c)},e=Object.keys(Ic),m=["."+Rc+":not(["+o+"])"].concat(e.map(function(c){return"."+c+":not(["+o+"])"})).join(", ");if(0!==m.length){var a=D(c.querySelectorAll(m));if(a.length>0){v("pending"),z("complete");var t=sc.begin("onTree"),f=a.reduce(function(c,l){try{var h=Xc(l);h&&c.push(h)}catch(c){u||c instanceof Nc&&console.error(c)}return c},[]);t(),gc(f,function(){v("active"),v("complete"),z("pending"),"function"==typeof l&&l()})}}}}function Gc(c){var l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,h=Xc(c);h&&gc([h],l)}var Jc=function(){var c=V,l=O.familyPrefix,h=O.replacementClass,v="svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;overflow:visible;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.fa-fw{width:1.25em}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;-webkit-box-sizing:border-box;box-sizing:border-box;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom right;transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom left;transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top left;transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:solid .08em #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{-webkit-transform:scale(1,-1);transform:scale(1,-1)}.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1,-1);transform:scale(-1,-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-rotate-90{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;position:relative;width:2em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.svg-inline--fa.fa-stack-1x{height:1em;width:1em}.svg-inline--fa.fa-stack-2x{height:2em;width:2em}.fa-inverse{color:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}";if("fa"!==l||h!==c){var z=new RegExp("\\.fa\\-","g"),e=new RegExp("\\."+c,"g");v=v.replace(z,"."+l+"-").replace(e,"."+h)}return v};var Qc=function(){function c(){y(this,c),this.definitions={}}return w(c,[{key:"add",value:function(){for(var c=this,l=arguments.length,h=Array(l),v=0;v1&&void 0!==arguments[1]?arguments[1]:{},h=l.transform,v=void 0===h?I:h,z=l.symbol,e=void 0!==z&&z,m=l.mask,a=void 0===m?null:m,s=l.title,t=void 0===s?null:s,f=l.classes,r=void 0===f?[]:f,M=l.attributes,i=void 0===M?{}:M,n=l.styles,H=void 0===n?{}:n;if(c){var V=c.prefix,o=c.iconName,C=c.icon;return ll(S({type:"icon"},c),function(){return cl(),O.autoA11y&&(t?i["aria-labelledby"]=O.replacementClass+"-title-"+B():i["aria-hidden"]="true"),hc({icons:{main:Zc(C),mask:a?Zc(a.icon):{found:!1,width:null,height:null,icon:{}}},prefix:V,iconName:o,transform:S({},I,v),symbol:e,title:t,extra:{attributes:i,styles:H,classes:r}})})}},function(c){var l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},h=(c||{}).icon?c:hl(c||{}),v=l.mask;return v&&(v=(v||{}).icon?v:hl(v||{})),vl(h,S({},l,{mask:v}))}),ml={noAuto:function(){var c;j({autoReplaceSvg:c=!1,observeMutations:c}),wc&&wc.disconnect()},dom:{i2svg:function(){var c=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(M){cl();var l=c.node,h=void 0===l?s:l,v=c.callback,z=void 0===v?function(){}:v;O.searchPseudoElements&&Uc(h),Kc(h,z)}},css:Jc,insertCss:function(){R(Jc())}},library:zl,parse:{transform:function(c){return xc(c)}},findIconDefinition:hl,icon:el,text:function(c){var l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},h=l.transform,v=void 0===h?I:h,z=l.title,e=void 0===z?null:z,m=l.classes,a=void 0===m?[]:m,s=l.attributes,t=void 0===s?{}:s,f=l.styles,r=void 0===f?{}:f;return ll({type:"text",content:c},function(){return cl(),vc({content:c,transform:S({},I,v),title:e,extra:{attributes:t,styles:r,classes:[O.familyPrefix+"-layers-text"].concat(k(a))}})})},layer:function(c){return ll({type:"layer"},function(){cl();var l=[];return c(function(c){Array.isArray(c)?c.map(function(c){l=l.concat(c.abstract)}):l=l.concat(c.abstract)}),[{tag:"span",attributes:{class:O.familyPrefix+"-layers"},children:l}]})}},al=function(){M&&O.autoReplaceSvg&&ml.dom.i2svg({node:s})};Object.defineProperty(ml,"config",{get:function(){return O},set:function(c){j(c)}}),function(c){try{c()}catch(c){if(!u)throw c}}(function(){r&&(a.FontAwesome||(a.FontAwesome=ml),T(function(){Object.keys(E.styles).length>0&&al(),O.observeMutations&&"function"==typeof MutationObserver&&function(c){if(t){var l=c.treeCallback,h=c.nodeCallback,v=c.pseudoElementsCallback;wc=new t(function(c){yc||D(c).forEach(function(c){if("childList"===c.type&&c.addedNodes.length>0&&!pc(c.addedNodes[0])&&(O.searchPseudoElements&&v(c.target),l(c.target)),"attributes"===c.type&&c.target.parentNode&&O.searchPseudoElements&&v(c.target.parentNode),"attributes"===c.type&&pc(c.target)&&~b.indexOf(c.attributeName))if("class"===c.attributeName){var z=Cc(X(c.target)),e=z.prefix,m=z.iconName;e&&c.target.setAttribute("data-prefix",e),m&&c.target.setAttribute("data-icon",m)}else h(c.target)})}),M&&wc.observe(s.getElementsByTagName("body")[0],{childList:!0,attributes:!0,characterData:!0,subtree:!0})}}({treeCallback:Kc,nodeCallback:Gc,pseudoElementsCallback:Uc})})),E.hooks=S({},E.hooks,{addPack:function(c,l){E.styles[c]=S({},E.styles[c]||{},l),Hc(),al()},addShims:function(c){var l;(l=E.shims).push.apply(l,k(c)),Hc(),al()}})})}(); \ No newline at end of file diff --git a/manual/cover/css/custom.css b/manual/cover/css/custom.css new file mode 100644 index 000000000..f67ba63f9 --- /dev/null +++ b/manual/cover/css/custom.css @@ -0,0 +1,190 @@ +/* fredericka-the-great-regular - latin */ +@font-face { + font-family: 'Fredericka the Great'; + font-style: normal; + font-weight: 400; + src: url('../fonts/fredericka-the-great-v10-latin-regular.eot'); /* IE9 Compat Modes */ + src: local(''), + url('../fonts/fredericka-the-great-v10-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/fredericka-the-great-v10-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/fredericka-the-great-v10-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/fredericka-the-great-v10-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/fredericka-the-great-v10-latin-regular.svg#FrederickatheGreat') format('svg'); /* Legacy iOS */ +} + +/* montserrat-regular - latin */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + src: url('../fonts/montserrat-v18-latin-regular.eot'); /* IE9 Compat Modes */ + src: local(''), + url('../fonts/montserrat-v18-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/montserrat-v18-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/montserrat-v18-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/montserrat-v18-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/montserrat-v18-latin-regular.svg#Montserrat') format('svg'); /* Legacy iOS */ +} + + +body { + margin: 0; + background-color: rgb(92,92,91); + display: flex; + flex-wrap: wrap; +} + +section { + width: 50%; +} + +img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.display { + display: flex; + justify-content: center; + align-items: center; + flex-wrap: wrap; + padding: 5% 10%; + background-color: #f89e9e; +} + +.front { + position: relative; + width: 500px; +} + +.front::before { + position: absolute; + content: ""; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(169.2deg,rgba(0,0,0,.5) 75%,rgba(255,255,255,.5) 91%),linear-gradient(169.2deg,rgba(0,0,0,.5) 15%,rgba(255,255,255,.5) 64%); +} + +.front .thumbnail { + height: 700px; + background-image: url(../img/front.jpg); + background-repeat: no-repeat; + background-size: cover; + box-shadow: 15px 10px 15px #925656; +} + +.sidebar { + background-color: #1bd; + width: 4%; + height: 700px; + font-family: 'Gruppo',cursive; + display: flex; + justify-content: space-evenly; + flex-direction: column; +} + +.sidebar span { + display: block; + color: #000; + text-transform: uppercase; + font-weight: 900; + text-align: center; + margin: 10px 0; + text-shadow: 0 6px 8px #000; + font-size: 20px; +} + +.down { + margin-top: 10px; +} + +.content { + position: absolute; + width: 100%; + height: 100%; + font-family: 'Montserrat',sans-serif; + text-align: center; + display: flex; + justify-content: space-between; + align-items: center; + flex-direction: column; +} + +.front .content .title { + color: white; + text-transform: capitalize; + text-shadow: 0 5px 15px #000; + font-family: 'Fredericka the Great',cursive; + font-size: 40px; + margin-top: 30px; +} + +.front .content .subtitle { + font-family: 'Montserrat',sans-serif; + color: #fff; + text-transform: uppercase; + font-size: 10px; + letter-spacing: 1.5px; +} + +.front .content .author { + font-family: 'Montserrat',sans-serif; + color: black; + letter-spacing: 5px; + font-weight: 900; + text-transform: uppercase; + font-size: 10px; +} + +.front .footer { + text-transform: uppercase; + font-size: 8px; + margin: 30px; + font-weight: 900; +} + +.header { + margin-top: 25px; + padding: 20px; +} + +.logo { + width: 25px; + height: 25px; +} + +.bar { + width: 80px; + height: 80px; +} + +.color { + color: #000; +} + + + +@media screen and (max-width:1367px) { + section { + width: 100%; + } + + .display { + padding: 20% 2%; + } + + .sidebar { + display: none; + } + + .front .thumbnail { + background-position: center; + } + + .sixthcover .front .title { + font-size: 42px; + } +} diff --git a/manual/cover/fonts/fredericka-the-great-v10-latin-regular.eot b/manual/cover/fonts/fredericka-the-great-v10-latin-regular.eot new file mode 100644 index 000000000..8a07a1688 Binary files /dev/null and b/manual/cover/fonts/fredericka-the-great-v10-latin-regular.eot differ diff --git a/manual/cover/fonts/fredericka-the-great-v10-latin-regular.svg b/manual/cover/fonts/fredericka-the-great-v10-latin-regular.svg new file mode 100644 index 000000000..67c556932 --- /dev/null +++ b/manual/cover/fonts/fredericka-the-great-v10-latin-regular.svg @@ -0,0 +1,7337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/manual/cover/fonts/fredericka-the-great-v10-latin-regular.ttf b/manual/cover/fonts/fredericka-the-great-v10-latin-regular.ttf new file mode 100644 index 000000000..ab2f1e098 Binary files /dev/null and b/manual/cover/fonts/fredericka-the-great-v10-latin-regular.ttf differ diff --git a/manual/cover/fonts/fredericka-the-great-v10-latin-regular.woff b/manual/cover/fonts/fredericka-the-great-v10-latin-regular.woff new file mode 100644 index 000000000..8f7ff3248 Binary files /dev/null and b/manual/cover/fonts/fredericka-the-great-v10-latin-regular.woff differ diff --git a/manual/cover/fonts/fredericka-the-great-v10-latin-regular.woff2 b/manual/cover/fonts/fredericka-the-great-v10-latin-regular.woff2 new file mode 100644 index 000000000..dc078b8a3 Binary files /dev/null and b/manual/cover/fonts/fredericka-the-great-v10-latin-regular.woff2 differ diff --git a/manual/cover/fonts/montserrat-v18-latin-regular.eot b/manual/cover/fonts/montserrat-v18-latin-regular.eot new file mode 100644 index 000000000..78a53ef41 Binary files /dev/null and b/manual/cover/fonts/montserrat-v18-latin-regular.eot differ diff --git a/manual/cover/fonts/montserrat-v18-latin-regular.svg b/manual/cover/fonts/montserrat-v18-latin-regular.svg new file mode 100644 index 000000000..6cc39cd4a --- /dev/null +++ b/manual/cover/fonts/montserrat-v18-latin-regular.svg @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/manual/cover/fonts/montserrat-v18-latin-regular.ttf b/manual/cover/fonts/montserrat-v18-latin-regular.ttf new file mode 100644 index 000000000..fe01d3f5f Binary files /dev/null and b/manual/cover/fonts/montserrat-v18-latin-regular.ttf differ diff --git a/manual/cover/fonts/montserrat-v18-latin-regular.woff b/manual/cover/fonts/montserrat-v18-latin-regular.woff new file mode 100644 index 000000000..24e4ebc51 Binary files /dev/null and b/manual/cover/fonts/montserrat-v18-latin-regular.woff differ diff --git a/manual/cover/fonts/montserrat-v18-latin-regular.woff2 b/manual/cover/fonts/montserrat-v18-latin-regular.woff2 new file mode 100644 index 000000000..c9f3817f6 Binary files /dev/null and b/manual/cover/fonts/montserrat-v18-latin-regular.woff2 differ diff --git a/manual/cover/img/front.jpg b/manual/cover/img/front.jpg new file mode 100644 index 000000000..cfa317346 Binary files /dev/null and b/manual/cover/img/front.jpg differ diff --git a/manual/cover/index.html b/manual/cover/index.html new file mode 100644 index 000000000..a18ae24df --- /dev/null +++ b/manual/cover/index.html @@ -0,0 +1,37 @@ + + + + + + + + Book Cover + + + + +
+
+
+
+
+
+

EPICYON

+

User Manual

+
+ +
+
+
+
+
+ + + + diff --git a/manual/manual.md b/manual/manual.md new file mode 100644 index 000000000..4eb4dbc66 --- /dev/null +++ b/manual/manual.md @@ -0,0 +1,334 @@ +# Contents +# Introduction +*The fediverse* is a set of federated servers, typically using a communication protocol called [ActivityPub](https://www.w3.org/TR/activitypub) which was devised by the [social working group](https://www.w3.org/wiki/Socialwg) within the World Wide Web Consortium (W3C). At present it is mostly used for [microblogging](https://en.wikipedia.org/wiki/Microblogging), although ActivityPub is sufficiently general that it can also be used for a variety of other purposes. + +The word *fediverse* (federated universe) appears to have originated around 2012 as the first [identi.ca](https://en.wikipedia.org/wiki/Identi.ca) website was ending and the [pump.io](https://en.wikipedia.org/wiki/Pump.io) project was beginning. The ActivityPub protocol was initially called *ActivityPump*, due to the influence which pump.io had upon its creation. Fediverse servers are typically referred to as "instances". + +Servers such as [Mastodon](https://github.com/mastodon/mastodon) are well known, but these are aimed at large scale deployments on powerful hardware running within data centers, making use of content distribution networks (CDN) and due to their large number of dependencies requiring someone with a high level of systems administration skill to maintain. Epicyon is designed for the opposite situation where it is only intended to have a single user or a small number of users (less than ten) running from your home location or on a modest VPS and where maintenance is extremely trivial such that it's possible to keep an instance running for long durations with minimal intervention. + +Epicyon is part of the "small web" category of internet software, in that it is intended to scale via federation rather than to scale vertically via resource intensive and expensive hardware. Think many small communicating nodes rather than a small number of large servers. Also, in spite of the prevailing great obsession with scale, not everything needs to. You can federate with a small number of servers for a particular purpose - such as running a club or hackspace - and that's ok. + +It is hardly possible to visit many sites on the web without your browser loading and running a large amount of javascript. Epicyon takes a minimalist approach where its web interface only uses HTML and CSS. You can disable javascript, or use a browser which doesn't have javascript capability, and the user experience is unchanged. Lack of javascript also rules out a large area of potential attack surface. + +Epicyon also includes some lightweight organizing features, such as calendar, events and sharing economy features. + +# Installation +## Prerequisites +You will need python version 3.7 or later. + +On a Debian based system: +``` bash +sudo apt install -y tor python3-socks imagemagick python3-setuptools python3-cryptography python3-dateutil python3-idna python3-requests python3-flake8 python3-django-timezone-field python3-pyqrcode python3-png python3-bandit libimage-exiftool-perl certbot nginx wget +``` +## Source code +The following instructions install Epicyon to the **/opt** directory. It's not essential that it be installed there, and it could be in any other preferred directory. + +Clone the repo, or if you downloaded the tarball then extract it into the **/opt** directory. +```bash +cd /opt +git clone https://gitlab.com/bashrc2/epicyon +``` +## Set permissions +Create a user for the server to run as: +```bash +sudo su +adduser --system --home=/opt/epicyon --group epicyon +chown -R epicyon:epicyon /opt/epicyon +``` +## News mirrors +The content for RSS feed links can be downloaded and mirrored, so that even if the original sources go offline the content remains readable. Link the RSS/newswire mirrors with. +```bash +mkdir /var/www/YOUR_DOMAIN +mkdir -p /opt/epicyon/accounts/newsmirror +ln -s /opt/epicyon/accounts/newsmirror /var/www/YOUR_DOMAIN/newsmirror +``` +## Create daemon +Typically the server will run from a *systemd* daemon. It can be set up as follows: +```bash +nano /etc/systemd/system/epicyon.service +``` + +Paste the following: +```bash +[Unit] +Description=epicyon +After=syslog.target +After=network.target + +[Service] +Type=simple +User=epicyon +Group=epicyon +WorkingDirectory=/opt/epicyon +ExecStart=/usr/bin/python3 /opt/epicyon/epicyon.py --port 443 --proxy 7156 --domain YOUR_DOMAIN --registration open --debug --log_login_failures +Environment=USER=epicyon +Environment=PYTHONUNBUFFERED=true +Restart=always +StandardError=syslog +CPUQuota=80% +ProtectHome=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectControlGroups=true +ProtectKernelLogs=true +ProtectHostname=true +ProtectClock=true +ProtectProc=invisible +ProcSubset=pid +PrivateTmp=true +PrivateUsers=true +PrivateDevices=true +PrivateIPC=true +MemoryDenyWriteExecute=true +NoNewPrivileges=true +LockPersonality=true +RestrictRealtime=true +RestrictSUIDSGID=true +RestrictNamespaces=true +SystemCallArchitectures=native + +[Install] +WantedBy=multi-user.target +``` + +Activate the daemon: +```bash +systemctl enable epicyon +systemctl start epicyon +``` +## Web server setup +Create a web server configuration. +```bash +nano /etc/nginx/sites-available/YOUR_DOMAIN +``` + +And paste the following: +```nginx +server { + listen 80; + listen [::]:80; + server_name YOUR_DOMAIN; + access_log /dev/null; + error_log /dev/null; + client_max_body_size 31m; + client_body_buffer_size 128k; + + limit_conn conn_limit_per_ip 10; + limit_req zone=req_limit_per_ip burst=10 nodelay; + + index index.html; + rewrite ^ https://$server_name$request_uri? permanent; +} + +server { + listen 443 ssl; + server_name YOUR_DOMAIN; + + gzip on; + gzip_disable "msie6"; + gzip_vary on; + gzip_proxied any; + gzip_min_length 1024; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_http_version 1.1; + gzip_types text/plain text/css text/vcard text/vcard+xml application/json application/ld+json application/javascript text/xml application/xml application/rdf+xml application/xml+rss text/javascript; + + ssl_stapling off; + ssl_stapling_verify off; + ssl on; + ssl_certificate /etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem; + #ssl_dhparam /etc/ssl/certs/YOUR_DOMAIN.dhparam; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + ssl_session_tickets off; + + add_header Content-Security-Policy "default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'"; + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Download-Options noopen; + add_header X-Permitted-Cross-Domain-Policies none; + add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always; + + access_log /dev/null; + error_log /dev/null; + + index index.html; + + location /newsmirror { + root /var/www/YOUR_DOMAIN; + try_files $uri =404; + } + + keepalive_timeout 70; + sendfile on; + + location / { + proxy_http_version 1.1; + client_max_body_size 31M; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forward-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forward-Proto http; + proxy_set_header X-Nginx-Proxy true; + proxy_temp_file_write_size 64k; + proxy_connect_timeout 10080s; + proxy_send_timeout 10080; + proxy_read_timeout 10080; + proxy_buffer_size 64k; + proxy_buffers 16 32k; + proxy_busy_buffers_size 64k; + proxy_redirect off; + proxy_request_buffering off; + proxy_buffering off; + proxy_pass http://localhost:7156; + tcp_nodelay on; + } +} +``` + +Enable the site: +```bash +ln -s /etc/nginx/sites-available/YOUR_DOMAIN /etc/nginx/sites-enabled/ +``` + +## On your internet router +Forward port 443 from your internet router to your server. If you have dynamic DNS make sure its configured. + +## Obtain a TLS certificate +```bash +systemctl stop nginx +certbot certonly -n --server https://acme-v02.api.letsencrypt.org/directory --standalone -d YOUR_DOMAIN --renew-by-default --agree-tos --email YOUR_EMAIL +systemctl start nginx +``` + +## Restart the web server +```bash +systemctl restart nginx +``` + +If you need to use [fail2ban](https://www.fail2ban.org) then failed login attempts can be found in **accounts/loginfailures.log**. + +If you are using the [Caddy web server](https://caddyserver.com) then see [caddy.example.conf](https://code.libreserver.org/bashrc/epicyon/raw/main/caddy.example.conf). + +Now you can navigate to your domain and register an account. The first account becomes the administrator. + +## Installing on Onion or i2p domains +If you don't have access to the clearnet, or prefer to avoid it, then it's possible to run an Epicyon instance easily from your laptop. There are scripts within the *deploy* directory which can be used to install an instance on a Debian or Arch/Parabola operating system. With some modification of package names they could be also used with other distros. + +Please be aware that such installations will not federate with ordinary fediverse instances on the clearnet, unless those instances have been specially modified to do so. But onion instances will federate with other onion instances and i2p instances with other i2p instances. + +# Upgrading +Unlike some other instance types, Epicyon is really easy to upgrade. It only requires a git pull to obtain the changes from the upstream repo, then set permissions and restart the daemon. +```bash +cd /opt/epicyon +git pull +chown -R epicyon:epicyon * +systemctl restart epicyon +``` +# Registering accounts +You will notice that within the systemd daemon the *registration* option is set to *open*. In a browser if you navigate to the URL of your instance then you should see a *Register* button. The first account to register becomes the administrator. + +To avoid spam signups, or overloading the system, there is a maximum number of accounts for the instance which by default is set to 10. + +# Logging in +In a browser if you navigate to the URL of your instance and enter the username and password that you previously registered. The first time that you log in it will show a series of introduction screens which prompt you to add a profile picture, name and bio description. + +# Account Profiles +## Initial setup +When you first register an account on the instance the first thing that you may want to do is to add more profile details and change your preferences. From the main timeline screen select the top banner to kove to your profile and then select the edit button, which usually looks like a pen and is adjacent to the logout icon. + +## Basic details +### Describe yourself +Add an appropriate description of youself, which doesn't resemble the type of thing which would appear on a spam account. When other fediverse users are judging a follow request from you they will want to know that you are a real person and not a spammer or troll. + +### Other fediverse accounts +If you have any other fediverse accounts on different instances then you might want to add URLs for those. You can set the languages which you can read, as [two letter abbreviations](https://en.wikipedia.org/wiki/ISO_639-1). This helps to avoid having posts from other people within your timeline which you can't read. + +### Expiring posts +You can set your posts to expire after a number of days. If this value is zero then the instance will keep your posts indefinitely. + +### Quitting Twitter +If you are coming to the fediverse as an exile from Twitter then you may want to select the option to remove any Twitter posts from your timeline. Sometimes people want to make a clean break from Twitter and have no further involvement with it. + +### Alternative contact details +You can set additional contact details, such as email, XMPP and Matrix addresses. So if people want to contact you for private [end-to-end secure](https://en.wikipedia.org/wiki/End-to-end_encryption) chat then they can do so. The fediverse was never designed for end-to-end security - it is primarily for public communications - and so it's better to leave secure private chat to the apps which are specialized for that purpose. + +### Filtering and blocking +If you want to block particular fediverse accounts or instances then you can enter those in the *blocked account* section. There should be one account per line. + +### Geolocation spoofing +Within the *filtering and blocking* section you can also set a city which will be used for geolocation spoofing. When you post a photo, instead of removing all metadata spoofed metadata will be added in order to consistently fool the machine learning systems behind web crawlers or scrapers, and create a [confirmation bias](https://en.wikipedia.org/wiki/Confirmation_bias) effect where the surveillance systems become increasingly confident in an erroneous conclusion. Setting a city somewhere near to your [time zone](https://en.wikipedia.org/wiki/Time_zone) is preferable, so that it matches your typical pattern of daily posting activity without giving away your real location. + +## Roles +If you are the administrator then within your profile settings you can also specify roles for other accounts on the instance. A small instance is like a ship with the roles being crew positions, and all members of the crew need to work together to keep the ship afloat. The current roles are: + +### Moderator +Is allowed to remove posts and deal with moderation reports. +### Editor +Editors can change the links in the left column and the RSS feeds within the right newswire column. +### Artist +Artists can change the colors and style of the web interface, using the *theme designer*. +### Counselor +A *counselor* is someone tasked with resolving disputes between users of the instance. They are permitted to send DMs to any user account on the instance. Obviously, this type of power can be abused and so the administrator should choose counselors with care. +### Devop +Devops are permitted to perform some routine administration functions, such as monitoring instance performance graphs. +# Following +On the main timeline screen at the top right of the centre column there is a search icon which looks like a magnifying glass. By convention within the fediverse the search function is also the way to look up and follow other people. Enter the handle (@name@domain) or URL of the profile page for the person that you want to follow and select *search*. If the account is found then its details will appear and you can choose to follow or not. + +Once you are following someone then selecting their profile picture and then the *unfollow* button will remove the follow. +# Creating posts +## Post scopes +## Attachments +## Events +## Maps +# The Timeline +## Layout +On a desktop system the main timeline screen has a multi-column layout. The main content containing posts is in the centre. To the left is a column containing useful web links. To the right is the newswire containing links from RSS feeds. + +At the top right of the centre column there are a few icons, for show/hide, calendar, search and creating a new post. + +Different timelines are listed at the top - inbox, DM, replies, outbox, etc - and more can be shown by selecting the *show/hide* icon. + +## Navigation +As a general principle of navigation selecting the top banner always takes you back to the previous screen, or if you are on the main timeline screen then it will alternate with your profile. + +At the bottom of the timeline there will usually be an arrow icon to go to the next page, and a list of page numbers. You can also move between pages using key shortcuts **ALT+SHIFT+>** and **ALT+SHIFT+<**. Key shortcuts exist for most navigation events, and you can customise them by selecting the *key shortcuts* link at the bottom of the left column. + +# Side columns +The links within the side columns are global to the instance, and only users having the *editor* role can change them. Since the number of accounts on the instance is expected to be small these links provide a common point of reference. + +## Links +Web links within the left column are intended to be generally useful or of interest to the users of the instance. They are similar to a blogroll. If you have the *editor* role there is an edit button at the top of the left column which can be used to add or remove links. Headers can also be added to group links into logical sections. + +## Newswire +The right column is the newswire column. It contains a list of links generated from RSS/Atom feeds. If you have the *editor* role then an edit icon will appear at the top of the right column, and the edit screen then allows you to add or remove feeds. +# Calendar +# Moderation +## Instance level moderation +## Moderator screen +## Account level moderation +## Emergencies +The fediverse is typically calmer than the centralized social networks, but there can be times when disputes break out and tempers become heated. In the worst cases this can lead to administrator burnout and instances shutting down. + +If you are the administrator and you are in a situation where you or the users on your instance are getting a lot of targeted harassement then you can put the instance into *broch mode*, which is a type of temporary allowlist which lasts for between one and two weeks. This prevents previously unknown instances from sending posts to your timelines, so adversaries can't create a lot of temporary instances for the purpose of attacking yours. + +A general observation is that it is difficult to maintain collective outrage at a high level for more than a week, so trolling campaigns tend to not last much longer than that. Broch mode allows you to ride out the storm, while retaining normal communications with friendly instances. + +To enable broch mode the administrator should edit their profile, go to the instance settings and select the option. Once enabled it will turn itself off automatically after 7-14 days. The somewhat uncertain deactivation time prevents an adversary from knowing when to begin a new flooding attempt, and after a couple of weeks they will be losing the motivation to continue. +# Themes +## Standard themes +## Theme customization +# Sharing economy +## Item ontology +## Federated shares +# Search +## Searching your posts +## Searching hashtags +## Searching shared items +# Building web communities diff --git a/scripts/mitm b/scripts/mitm new file mode 100755 index 000000000..09cb8cc9b --- /dev/null +++ b/scripts/mitm @@ -0,0 +1,7 @@ +#!/bin/bash +journalctl -u epicyon | grep 'MITM:' > .mitm_events.txt +if [ ! -f .mitm_events.txt ]; then + echo 'No MITM events' +else + cat .mitm_events.txt +fi diff --git a/tests.py b/tests.py index 83643acdf..7f4fb1449 100644 --- a/tests.py +++ b/tests.py @@ -55,6 +55,7 @@ from follow import send_follow_request_via_server from follow import send_unfollow_request_via_server from siteactive import site_is_active from utils import remove_inverted_text +from utils import remove_square_capitals from utils import standardize_text from utils import remove_eol from utils import text_in_file @@ -7562,6 +7563,15 @@ def _test_uninvert(): print('result: ' + result) assert result == expected + text = '🅻🅴🆅🅸🅰🆃🅰🆁 abc' + expected = "LEVIATAR abc" + result = remove_square_capitals(text, 'en') + if result != expected: + print('expected: ' + expected) + print('result: ' + result) + print('text: ' + text) + assert result == expected + text = '

Some ordinary text

ʇsǝʇ ɐ sı sıɥʇ

' expected = "

Some ordinary text

this is a test

" result = remove_inverted_text(text, 'en') diff --git a/translations/ar.json b/translations/ar.json index 5b94f68fd..7bc139782 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -594,5 +594,6 @@ "Site DevOps": "DevOps الموقع", "A list of devops nicknames. One per line.": "قائمة بأسماء المطورين. واحد في كل سطر.", "devops": "devops", - "Reject spam accounts": "رفض حسابات البريد العشوائي" + "Reject spam accounts": "رفض حسابات البريد العشوائي", + "User Manual": "دليل الاستخدام" } diff --git a/translations/bn.json b/translations/bn.json index bdd4de2eb..b455a0a9c 100644 --- a/translations/bn.json +++ b/translations/bn.json @@ -594,5 +594,6 @@ "Site DevOps": "সাইট DevOps", "A list of devops nicknames. One per line.": "ডেভপস ডাকনামের একটি তালিকা। প্রতি লাইনে একটি।", "devops": "devops", - "Reject spam accounts": "স্প্যাম অ্যাকাউন্ট প্রত্যাখ্যান করুন" + "Reject spam accounts": "স্প্যাম অ্যাকাউন্ট প্রত্যাখ্যান করুন", + "User Manual": "ব্যবহার বিধি" } diff --git a/translations/ca.json b/translations/ca.json index 1384007cc..c3737d855 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -594,5 +594,6 @@ "Site DevOps": "Lloc DevOps", "A list of devops nicknames. One per line.": "Una llista de sobrenoms de devops. Un per línia.", "devops": "devops", - "Reject spam accounts": "Rebutja els comptes de correu brossa" + "Reject spam accounts": "Rebutja els comptes de correu brossa", + "User Manual": "Manual d'usuari" } diff --git a/translations/cy.json b/translations/cy.json index 1f7245ab7..3414d01be 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -594,5 +594,6 @@ "Site DevOps": "Gwefan DevOps", "A list of devops nicknames. One per line.": "Mae rhestr o devops llysenwau. Un i bob llinell.", "devops": "devops", - "Reject spam accounts": "Gwrthod cyfrifon sbam" + "Reject spam accounts": "Gwrthod cyfrifon sbam", + "User Manual": "Llawlyfr Defnyddiwr" } diff --git a/translations/de.json b/translations/de.json index 3e9b6f24b..cdd124108 100644 --- a/translations/de.json +++ b/translations/de.json @@ -594,5 +594,6 @@ "Site DevOps": "Site-DevOps", "A list of devops nicknames. One per line.": "Eine Liste von Entwickler-Spitznamen. Eine pro Zeile.", "devops": "devops", - "Reject spam accounts": "Gwrthod cyfrifon sbam" + "Reject spam accounts": "Gwrthod cyfrifon sbam", + "User Manual": "Benutzerhandbuch" } diff --git a/translations/el.json b/translations/el.json index 809695903..c966954d5 100644 --- a/translations/el.json +++ b/translations/el.json @@ -594,5 +594,6 @@ "Site DevOps": "DevOps ιστότοπου", "A list of devops nicknames. One per line.": "Μια λίστα με ψευδώνυμα devops. Ένα ανά γραμμή.", "devops": "devops", - "Reject spam accounts": "Gwrthod cyfrifon sbam" + "Reject spam accounts": "Gwrthod cyfrifon sbam", + "User Manual": "Εγχειρίδιο χρήστη" } diff --git a/translations/en.json b/translations/en.json index 95bf94265..584084820 100644 --- a/translations/en.json +++ b/translations/en.json @@ -594,5 +594,6 @@ "Site DevOps": "Site DevOps", "A list of devops nicknames. One per line.": "A list of devops nicknames. One per line.", "devops": "devops", - "Reject spam accounts": "Reject spam accounts" + "Reject spam accounts": "Reject spam accounts", + "User Manual": "User Manual" } diff --git a/translations/es.json b/translations/es.json index bb1a16ffe..7447e5b94 100644 --- a/translations/es.json +++ b/translations/es.json @@ -594,5 +594,6 @@ "Site DevOps": "DevOps del sitio", "A list of devops nicknames. One per line.": "Una lista de apodos de devops. Uno por línea.", "devops": "devops", - "Reject spam accounts": "Rechazar cuentas de spam" + "Reject spam accounts": "Rechazar cuentas de spam", + "User Manual": "Manual de usuario" } diff --git a/translations/fr.json b/translations/fr.json index 80924412a..0e07445c5 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -594,5 +594,6 @@ "Site DevOps": "DevOps du site", "A list of devops nicknames. One per line.": "Une liste de surnoms de devops. Un par ligne.", "devops": "devops", - "Reject spam accounts": "Rejeter les comptes de spam" + "Reject spam accounts": "Rejeter les comptes de spam", + "User Manual": "Manuel de l'Utilisateur" } diff --git a/translations/ga.json b/translations/ga.json index 6109f82a2..17551e459 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -594,5 +594,6 @@ "Site DevOps": "Suíomh DevOps", "A list of devops nicknames. One per line.": "Tá liosta devops leasainmneacha. Ceann in aghaidh an líne.", "devops": "devops", - "Reject spam accounts": "Diúltaigh cuntais turscair" + "Reject spam accounts": "Diúltaigh cuntais turscair", + "User Manual": "Lámhleabhar Úsáideora" } diff --git a/translations/hi.json b/translations/hi.json index 6c6bf7d86..8dd495d9d 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -594,5 +594,6 @@ "Site DevOps": "साइट देवऑप्स", "A list of devops nicknames. One per line.": "देवोप्स उपनामों की एक सूची। प्रति पंक्ति एक।", "devops": "devops", - "Reject spam accounts": "स्पैम खातों को अस्वीकार करें" + "Reject spam accounts": "स्पैम खातों को अस्वीकार करें", + "User Manual": "उपयोगकर्ता पुस्तिका" } diff --git a/translations/it.json b/translations/it.json index aa501515f..313e8edb8 100644 --- a/translations/it.json +++ b/translations/it.json @@ -594,5 +594,6 @@ "Site DevOps": "Sito DevOps", "A list of devops nicknames. One per line.": "Un elenco di soprannomi devops. Uno per riga.", "devops": "devops", - "Reject spam accounts": "Rifiuta gli account spam" + "Reject spam accounts": "Rifiuta gli account spam", + "User Manual": "Manuale d'uso" } diff --git a/translations/ja.json b/translations/ja.json index 7ad0ff780..56e567ad8 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -594,5 +594,6 @@ "Site DevOps": "サイト DevOps", "A list of devops nicknames. One per line.": "DevOps ニックネームのリスト。 1 行に 1 つ。", "devops": "devops", - "Reject spam accounts": "スパムアカウントを拒否" + "Reject spam accounts": "スパムアカウントを拒否", + "User Manual": "ユーザーマニュアル" } diff --git a/translations/ko.json b/translations/ko.json index a287d2f72..833fef494 100644 --- a/translations/ko.json +++ b/translations/ko.json @@ -594,5 +594,6 @@ "Site DevOps": "사이트 DevOps", "A list of devops nicknames. One per line.": "데브옵스 닉네임 목록입니다. 한 줄에 하나씩.", "devops": "devops", - "Reject spam accounts": "스팸 계정 거부" + "Reject spam accounts": "스팸 계정 거부", + "User Manual": "사용자 매뉴얼" } diff --git a/translations/ku.json b/translations/ku.json index 4e915e40e..5de6b24a0 100644 --- a/translations/ku.json +++ b/translations/ku.json @@ -594,5 +594,6 @@ "Site DevOps": "Malpera DevOps", "A list of devops nicknames. One per line.": "Lîsteya navên devops. Her rêzek yek.", "devops": "devops", - "Reject spam accounts": "Hesabên spam red bikin" + "Reject spam accounts": "Hesabên spam red bikin", + "User Manual": "Manual Bikarhêner" } diff --git a/translations/nl.json b/translations/nl.json index dc6b7eb64..96e70b4a7 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -594,5 +594,6 @@ "Site DevOps": "Site DevOps", "A list of devops nicknames. One per line.": "Een lijst met devops-bijnamen. Een per regel.", "devops": "devops", - "Reject spam accounts": "Spamaccounts afwijzen" + "Reject spam accounts": "Spamaccounts afwijzen", + "User Manual": "Handleiding" } diff --git a/translations/oc.json b/translations/oc.json index 25bfd8613..cd42bc632 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -590,5 +590,6 @@ "Site DevOps": "Site DevOps", "A list of devops nicknames. One per line.": "A list of devops nicknames. One per line.", "devops": "devops", - "Reject spam accounts": "Reject spam accounts" + "Reject spam accounts": "Reject spam accounts", + "User Manual": "User Manual" } diff --git a/translations/pl.json b/translations/pl.json index 077724aad..5251a3ba0 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -594,5 +594,6 @@ "Site DevOps": "Deweloperzy witryny", "A list of devops nicknames. One per line.": "Lista pseudonimów Devopa. Jeden na linię.", "devops": "devops", - "Reject spam accounts": "Odrzuć konta spamowe" + "Reject spam accounts": "Odrzuć konta spamowe", + "User Manual": "Instrukcja obsługi" } diff --git a/translations/pt.json b/translations/pt.json index ae1b929c0..cdb49560d 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -594,5 +594,6 @@ "Site DevOps": "Site DevOps", "A list of devops nicknames. One per line.": "Uma lista de apelidos de devops. Um por linha.", "devops": "devops", - "Reject spam accounts": "Rejeitar contas de spam" + "Reject spam accounts": "Rejeitar contas de spam", + "User Manual": "Manual do usuário" } diff --git a/translations/ru.json b/translations/ru.json index 5553be1a6..c3dbdfb8b 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -594,5 +594,6 @@ "Site DevOps": "DevOps сайта", "A list of devops nicknames. One per line.": "Список псевдонимов devops. По одному на строку.", "devops": "devops", - "Reject spam accounts": "Отклонить спам-аккаунты" + "Reject spam accounts": "Отклонить спам-аккаунты", + "User Manual": "Руководство пользователя" } diff --git a/translations/sw.json b/translations/sw.json index 19797f9c9..5fa4afbd3 100644 --- a/translations/sw.json +++ b/translations/sw.json @@ -594,5 +594,6 @@ "Site DevOps": "Tovuti ya DevOps", "A list of devops nicknames. One per line.": "Orodha ya majina ya utani ya devops. Moja kwa kila mstari.", "devops": "devops", - "Reject spam accounts": "Kataa akaunti za barua taka" + "Reject spam accounts": "Kataa akaunti za barua taka", + "User Manual": "Mwongozo wa mtumiaji" } diff --git a/translations/tr.json b/translations/tr.json index 10a912f0e..9bc1e42d7 100644 --- a/translations/tr.json +++ b/translations/tr.json @@ -594,5 +594,6 @@ "Site DevOps": "Site DevOps", "A list of devops nicknames. One per line.": "Devops takma adlarının listesi. Her satıra bir tane.", "devops": "devops", - "Reject spam accounts": "Spam hesapları reddet" + "Reject spam accounts": "Spam hesapları reddet", + "User Manual": "Kullanım kılavuzu" } diff --git a/translations/uk.json b/translations/uk.json index f878b705d..cf338ecbc 100644 --- a/translations/uk.json +++ b/translations/uk.json @@ -594,5 +594,6 @@ "Site DevOps": "Сайт DevOps", "A list of devops nicknames. One per line.": "Список ніків devops. По одному на рядок.", "devops": "devops", - "Reject spam accounts": "Відхилити спам-акаунти" + "Reject spam accounts": "Відхилити спам-акаунти", + "User Manual": "Посібник користувача" } diff --git a/translations/yi.json b/translations/yi.json index 90008d839..c1207aa94 100644 --- a/translations/yi.json +++ b/translations/yi.json @@ -594,5 +594,6 @@ "Site DevOps": "וועבזייטל DevOps", "A list of devops nicknames. One per line.": "א רשימה פון דיוואָפּס ניקניימז. איינער פּער שורה.", "devops": "devops", - "Reject spam accounts": "אָפּוואַרפן ספּאַם אַקאַונץ" + "Reject spam accounts": "אָפּוואַרפן ספּאַם אַקאַונץ", + "User Manual": "באנוצער אנווייזער" } diff --git a/translations/zh.json b/translations/zh.json index 1d435f276..3ccbda6ca 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -594,5 +594,6 @@ "Site DevOps": "站点 DevOps", "A list of devops nicknames. One per line.": "devops 昵称列表。 每行一个。", "devops": "devops", - "Reject spam accounts": "拒绝垃圾邮件帐户" + "Reject spam accounts": "拒绝垃圾邮件帐户", + "User Manual": "用户手册" } diff --git a/utils.py b/utils.py index fce00339e..16cc94ad9 100644 --- a/utils.py +++ b/utils.py @@ -3915,3 +3915,21 @@ def remove_inverted_text(text: str, system_language: str) -> str: new_text += separator return new_text + + +def remove_square_capitals(text: str, system_language: str) -> str: + """Removes any square capital text from the given string + """ + if system_language != 'en': + return text + offset = ord('A') + start_value = ord('🅰') + end_value = start_value + 26 + result = '' + for text_ch in text: + text_value = ord(text_ch) + if text_value < start_value or text_value > end_value: + result += text_ch + else: + result += chr(offset + text_value - start_value) + return result diff --git a/webapp_column_left.py b/webapp_column_left.py index 6d7225e2a..4a1e76df7 100644 --- a/webapp_column_left.py +++ b/webapp_column_left.py @@ -346,6 +346,9 @@ def get_left_column_content(base_dir: str, nickname: str, domain_full: str, html_str += \ '' + html_str += \ + '' html_str += \ '' diff --git a/webapp_manual.py b/webapp_manual.py new file mode 100644 index 000000000..59a6c1868 --- /dev/null +++ b/webapp_manual.py @@ -0,0 +1,69 @@ +__filename__ = "webapp_about.py" +__author__ = "Bob Mottram" +__license__ = "AGPL3+" +__version__ = "1.3.0" +__maintainer__ = "Bob Mottram" +__email__ = "bob@libreserver.org" +__status__ = "Production" +__module_group__ = "Web Interface" + +import os +from shutil import copyfile +from utils import get_config_param +from webapp_utils import html_header_with_website_markup +from webapp_utils import html_footer +from markdown import markdown_example_numbers +from markdown import markdown_to_html + + +def html_manual(base_dir: str, http_prefix: str, + domain_full: str, onion_domain: str, translate: {}, + system_language: str) -> str: + """Show the user manual screen + """ + manual_filename = base_dir + '/manual/manual.md' + admin_nickname = get_config_param(base_dir, 'admin') + if os.path.isfile(base_dir + '/accounts/manual.md'): + manual_filename = base_dir + '/accounts/manual.md' + + if os.path.isfile(base_dir + '/accounts/login-background-custom.jpg'): + if not os.path.isfile(base_dir + '/accounts/login-background.jpg'): + copyfile(base_dir + '/accounts/login-background-custom.jpg', + base_dir + '/accounts/login-background.jpg') + + manual_text = 'User Manual.' + if os.path.isfile(manual_filename): + with open(manual_filename, 'r', + encoding='utf-8') as fp_manual: + md_text = markdown_example_numbers(fp_manual.read()) + manual_text = markdown_to_html(md_text) + + manual_form = '' + css_filename = base_dir + '/epicyon-profile.css' + if os.path.isfile(base_dir + '/epicyon.css'): + css_filename = base_dir + '/epicyon.css' + + instance_title = \ + get_config_param(base_dir, 'instanceTitle') + manual_form = \ + html_header_with_website_markup(css_filename, instance_title, + http_prefix, domain_full, + system_language) + manual_form += \ + '
' + manual_text + '
' + if onion_domain: + manual_form += \ + '
\n' + \ + '

' + \ + 'http://' + onion_domain + '

\n
\n' + if admin_nickname: + admin_actor = '/users/' + admin_nickname + manual_form += \ + '
\n' + \ + '

' + \ + translate['Administered by'] + ' ' + admin_nickname + '. ' + \ + translate['Version'] + ' ' + __version__ + \ + '

\n
\n' + manual_form += html_footer() + return manual_form diff --git a/webapp_media.py b/webapp_media.py index 9d4d3e5db..db1ba6250 100644 --- a/webapp_media.py +++ b/webapp_media.py @@ -33,9 +33,32 @@ def load_peertube_instances(base_dir: str, peertube_instances: []) -> None: def _add_embedded_video_from_sites(translate: {}, content: str, peertube_instances: [], - width: int, height: int) -> str: + width: int, height: int, + domain: str) -> str: """Adds embedded videos """ + if '\n\n' + \ + '' + \ + '\n\n' + return content + if '>vimeo.com/' in content: url = content.split('>vimeo.com/')[1] if '<' in url: @@ -345,10 +368,11 @@ def _add_embedded_video(translate: {}, content: str) -> str: def add_embedded_elements(translate: {}, content: str, - peertube_instances: []) -> str: + peertube_instances: [], domain: str) -> str: """Adds embedded elements for various media types """ content = _add_embedded_video_from_sites(translate, content, - peertube_instances, 400, 300) + peertube_instances, + 400, 300, domain) content = _add_embedded_audio(translate, content) return _add_embedded_video(translate, content) diff --git a/webapp_post.py b/webapp_post.py index 7c4eec8f8..d3d529a57 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -2236,7 +2236,7 @@ def individual_post_as_html(signing_priv_key_pem: str, if not post_is_sensitive: content_str = object_content + attachment_str content_str = add_embedded_elements(translate, content_str, - peertube_instances) + peertube_instances, domain) content_str = insert_question(base_dir, translate, nickname, domain, content_str, post_json_object, @@ -2258,7 +2258,8 @@ def individual_post_as_html(signing_priv_key_pem: str, cw_content_str = object_content + attachment_str if not is_patch: cw_content_str = add_embedded_elements(translate, cw_content_str, - peertube_instances) + peertube_instances, + domain_full) cw_content_str = \ insert_question(base_dir, translate, nickname, domain, cw_content_str, post_json_object, page_number)