├── LICENSE ├── README.md ├── _locales ├── de │ └── messages.json └── en │ └── messages.json ├── background.js ├── css ├── icon │ ├── icon.css │ ├── icon.css.map │ └── icon.scss ├── jquery.qtip.min.css ├── loader │ ├── loader.css │ ├── loader.css.map │ └── loader.scss ├── options.css ├── tooltip.css └── tutorial │ ├── tutorial.css │ ├── tutorial.css.backup │ ├── tutorial.css.map │ └── tutorial.scss ├── icon.html ├── img ├── TORPEDO_Icon.svg ├── TORPEDO_fullLockup.svg ├── advice.png ├── error38.png ├── error64.png ├── examples │ ├── de │ │ ├── blue_case_de.svg │ │ ├── green_case_de.svg │ │ ├── red_case_de.svg │ │ ├── settings_de.png │ │ ├── simple-grey_case_contextmenu_de.svg │ │ ├── simple-grey_case_no-phish_de.svg │ │ ├── simple-grey_case_phish_de.svg │ │ ├── warning-grey_case_no-phish_de.svg │ │ └── warning-grey_case_phish_de.svg │ └── en │ │ ├── blue_case_en.svg │ │ ├── green_case_en.svg │ │ ├── red_case_en.svg │ │ ├── settings_en.png │ │ ├── simple-grey_case_contextmenu_en.svg │ │ ├── simple-grey_case_no-phish_en.svg │ │ ├── simple-grey_case_phish_en.svg │ │ ├── warning-grey_case_no-phish_en.svg │ │ └── warning-grey_case_phish_en.svg ├── icon38.png ├── icon64.png ├── info.png ├── none38.png ├── none64.png ├── warning.png └── warning2.png ├── js ├── contentscript.js ├── icon.js ├── jquery-3.4.1.min.js ├── jquery.qtip.min.js ├── options.js ├── publicsuffixlist.js ├── punycode.min.js ├── redirect.js ├── status.js ├── timer.js ├── tooltip.js └── tutorial.js ├── manifest.json ├── options.html └── tutorial.html /README.md: -------------------------------------------------------------------------------- 1 | # TORPEDO - TOoltip-poweRed Phishing Email DetectiOn 2 | 3 | ## Download 4 | 5 | Das Add-on kann von der offiziellen [Add-on Webseite](https://addons.mozilla.org/de/thunderbird/addon/torpedo-phishing-detection/) von Mozilla heruntergeladen werden. 6 | 7 | ## INSTALLATION (nicht notwendig, wenn Sie das Add On im Store herunterladen) 8 | 9 | ###### Deutsch / German 10 | 11 | **SCHRITT 1** 12 | WINDOWS: 13 | Markieren Sie alle Dateien im Torpedo-Ordner mit STRG-A und führen Sie einen Rechtsklick aus. Nun wählen Sie "Senden an ... ZIP-komprimierten Ordner". Der komprimierte Ordner muss jetzt in "torpedo.xpi" umbenannt werden. 14 | 15 | MAC OS X: 16 | Markieren Sie alle Dateien im Torpedo-Ordner mit CMD-A und führen Sie einen Rechtsklick aus. Wählen Sie "X Objekte komprimieren". Der komprimierte Ordner muss jetzt in "torpedo.xpi" umbenannt werden. 17 | 18 | LINUX: 19 | Navigieren Sie in den Torpedo-Ordner mit "cd /your-git-repository/torpedo/". Nun geben Sie "zip -r ../torpedo.xpi \*" ins Terminal ein. Die "torpedo.xpi" Datei befindet sich nun außerhalb des Torpedo-Ordners. 20 | 21 | **SCHRITT 2** 22 | Öffnen Sie Thunderbird und klicken Sie auf Einstellungen -> "Add-Ons". Dort wählen Sie das Einstellungen-Symbol oben in der Mitte. Daraufhin öffnen sich mehrere Optionen. Wählen Sie "Add On aus Datei installieren". Suchen Sie die torpedo.xpi-Datei, und installieren Sie diese. Jetzt sollte Thunderbird neu gestartet werden, damit die Änderungen wirksam werden. 23 | 24 | ###### Englisch / English 25 | 26 | **STEP 1** 27 | WINDOWS: 28 | Select every file inside the torpedo folder with STRG-A and use the right mouse key. Now you choose "Send to ... ZIP-compressed folder". The compressed folder has to be renamed in "torpedo.xpi". 29 | 30 | MAC OS X: 31 | Select every file inside the torpedo folder with CMD-A and use the right mouse key. Now you choose "Compress X Items". The compressed folder has to be renamed in "torpedo.xpi". 32 | 33 | LINUX: 34 | Navigate into the torpedo folder with "cd /your-git-repository/torpedo/". Now enter "zip -r ../torpedo.xpi \*" into the terminal. The file "torpedo.xpi" is located outside of your torpedo folder. 35 | 36 | **STEP 2** 37 | Open Thunderbird and choose Tools -> "Add Ons". In the Add Ons screen, click on the settings symbol at the top center. Here you will find multiple options. Choose "Install Add On from file" and search for "torpedo.xpi". After the installation, Thunderbird should be restarted for the changes to take effect. 38 | 39 | ## Lizenz 40 | 41 | TORPEDO ist mit der GPLv3 lizenziert. 42 | -------------------------------------------------------------------------------- /css/icon/icon.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | -webkit-box-sizing: border-box; 5 | box-sizing: border-box; 6 | } 7 | 8 | body { 9 | width: 25rem; 10 | font-size: 2rem; 11 | } 12 | 13 | .buttons { 14 | width: 90%; 15 | margin: 2rem auto; 16 | } 17 | 18 | button { 19 | border-radius: 10px; 20 | border: none; 21 | background-color: #1a509d; 22 | color: white; 23 | padding: 1rem 2rem; 24 | cursor: pointer; 25 | display: block; 26 | width: 100%; 27 | margin-top: 1rem; 28 | } 29 | 30 | button:hover:not(:last-child) { 31 | background-color: #2166c9; 32 | } 33 | 34 | .working { 35 | background: green; 36 | cursor: initial; 37 | } 38 | 39 | .error { 40 | background: #cc0000; 41 | cursor: help; 42 | } 43 | 44 | .error:hover { 45 | background: red; 46 | } 47 | /*# sourceMappingURL=icon.css.map */ -------------------------------------------------------------------------------- /css/icon/icon.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "AAMA,AAAA,CAAC,CAAC;EACA,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;EACV,UAAU,EAAE,UAAU;CACvB;;AACD,AAAA,IAAI,CAAC;EACH,KAAK,EAAE,KAAK;EACZ,SAAS,EAAE,IAAI;CAChB;;AACD,AAAA,QAAQ,CAAC;EACP,KAAK,EAAE,GAAG;EACV,MAAM,EAAE,SAAS;CAClB;;AACD,AAAA,MAAM,CAAC;EACL,aAAa,EAAE,IAAI;EACnB,MAAM,EAAE,IAAI;EACZ,gBAAgB,EAnBH,OAAO;EAoBpB,KAAK,EAAE,KAAK;EACZ,OAAO,EAAE,SAAS;EAClB,MAAM,EAAE,OAAO;EACf,OAAO,EAAE,KAAK;EACd,KAAK,EAAE,IAAI;EACX,UAAU,EAAE,IAAI;CACjB;;AAMD,AAAA,MAAM,AAAA,MAAM,AAAA,IAAK,CAAA,WAAW,EAAE;EAC5B,gBAAgB,EAAE,OAA2B;CAC9C;;AACD,AAAA,QAAQ,CAAC;EACP,UAAU,EAAE,KAA2B;EACvC,MAAM,EAAE,OAAO;CAChB;;AACD,AAAA,MAAM,CAAC;EAIL,UAAU,EAAE,OAAyB;EAErC,MAAM,EAAE,IAAI;CACb;;AAPD,AACE,MADI,AACH,MAAM,CAAC;EACN,UAAU,EAAE,GAAyB;CACtC", 4 | "sources": [ 5 | "icon.scss" 6 | ], 7 | "names": [], 8 | "file": "icon.css" 9 | } -------------------------------------------------------------------------------- /css/icon/icon.scss: -------------------------------------------------------------------------------- 1 | // VARIABLES 2 | $torpedo-grey: #bfb9b9; 3 | $torpedo-green: green; 4 | $torpedo-blue: #1a509d; 5 | $torpedo-red: red; 6 | 7 | * { 8 | margin: 0; 9 | padding: 0; 10 | box-sizing: border-box; 11 | } 12 | body { 13 | width: 25rem; 14 | font-size: 2rem; 15 | } 16 | .buttons { 17 | width: 90%; 18 | margin: 2rem auto; 19 | } 20 | button { 21 | border-radius: 10px; 22 | border: none; 23 | background-color: $torpedo-blue; 24 | color: white; 25 | padding: 1rem 2rem; 26 | cursor: pointer; 27 | display: block; 28 | width: 100%; 29 | margin-top: 1rem; 30 | } 31 | 32 | // button:not(:last-child) { 33 | // border-bottom: none; 34 | // } 35 | 36 | button:hover:not(:last-child) { 37 | background-color: lighten($torpedo-blue, 10%); 38 | } 39 | .working { 40 | background: lighten($torpedo-green, 0%); 41 | cursor: initial; 42 | } 43 | .error { 44 | &:hover { 45 | background: lighten($torpedo-red, 0%); 46 | } 47 | background: darken($torpedo-red, 10%); 48 | // background: $torpedo-red; 49 | cursor: help; 50 | } 51 | -------------------------------------------------------------------------------- /css/jquery.qtip.min.css: -------------------------------------------------------------------------------- 1 | /* qTip2 v2.2.0 basic css3 | qtip2.com | Licensed MIT, GPL | Sat Mar 15 2014 09:24:04 */ 2 | .qtip{position:absolute;left:-28000px;top:-28000px;display:none;max-width:280px;min-width:50px;font-size:10.5px;line-height:12px;direction:ltr;box-shadow:none;padding:0}.qtip-content{position:relative;padding:5px 9px;overflow:hidden;text-align:left;word-wrap:break-word}.qtip-titlebar{position:relative;padding:5px 35px 5px 10px;overflow:hidden;border-width:0 0 1px;font-weight:700}.qtip-titlebar+.qtip-content{border-top-width:0!important}.qtip-close{position:absolute;right:-9px;top:-9px;cursor:pointer;outline:medium none;border-width:1px;border-style:solid;border-color:transparent}.qtip-titlebar .qtip-close{right:4px;top:50%;margin-top:-9px}* html .qtip-titlebar .qtip-close{top:16px}.qtip-titlebar .ui-icon,.qtip-icon .ui-icon{display:block;text-indent:-1000em;direction:ltr}.qtip-icon,.qtip-icon .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;text-decoration:none}.qtip-icon .ui-icon{width:18px;height:14px;line-height:14px;text-align:center;text-indent:0;font:400 bold 10px/13px Tahoma,sans-serif;color:inherit;background:transparent none no-repeat -100em -100em}.qtip-focus{}.qtip-hover{}.qtip-default{border-width:1px;border-style:solid;border-color:#F1D031;background-color:#FFFFA3;color:#555}.qtip-default .qtip-titlebar{background-color:#FFEF93}.qtip-default .qtip-icon{border-color:#CCC;background:#F1F1F1;color:#777}.qtip-default .qtip-titlebar .qtip-close{border-color:#AAA;color:#111} .qtip-light{background-color:#fff;border-color:#E2E2E2;color:#454545}.qtip-light .qtip-titlebar{background-color:#f1f1f1} .qtip-dark{background-color:#505050;border-color:#303030;color:#f3f3f3}.qtip-dark .qtip-titlebar{background-color:#404040}.qtip-dark .qtip-icon{border-color:#444}.qtip-dark .qtip-titlebar .ui-state-hover{border-color:#303030} .qtip-cream{background-color:#FBF7AA;border-color:#F9E98E;color:#A27D35}.qtip-cream .qtip-titlebar{background-color:#F0DE7D}.qtip-cream .qtip-close .qtip-icon{background-position:-82px 0} .qtip-red{background-color:#F78B83;border-color:#D95252;color:#912323}.qtip-red .qtip-titlebar{background-color:#F06D65}.qtip-red .qtip-close .qtip-icon{background-position:-102px 0}.qtip-red .qtip-icon{border-color:#D95252}.qtip-red .qtip-titlebar .ui-state-hover{border-color:#D95252} .qtip-green{background-color:#CAED9E;border-color:#90D93F;color:#3F6219}.qtip-green .qtip-titlebar{background-color:#B0DE78}.qtip-green .qtip-close .qtip-icon{background-position:-42px 0} .qtip-blue{background-color:#E5F6FE;border-color:#ADD9ED;color:#5E99BD}.qtip-blue .qtip-titlebar{background-color:#D0E9F5}.qtip-blue .qtip-close .qtip-icon{background-position:-2px 0}.qtip-shadow{-webkit-box-shadow:1px 1px 3px 1px rgba(0,0,0,.15);-moz-box-shadow:1px 1px 3px 1px rgba(0,0,0,.15);box-shadow:1px 1px 3px 1px rgba(0,0,0,.15)}.qtip-rounded,.qtip-tipsy,.qtip-bootstrap{-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.qtip-rounded .qtip-titlebar{-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.qtip-youtube{-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 3px #333;-moz-box-shadow:0 0 3px #333;box-shadow:0 0 3px #333;color:#fff;border-width:0;background:#4A4A4A;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#4A4A4A),color-stop(100%,#000));background-image:-webkit-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-moz-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-ms-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-o-linear-gradient(top,#4A4A4A 0,#000 100%)}.qtip-youtube .qtip-titlebar{background-color:#4A4A4A;background-color:rgba(0,0,0,0)}.qtip-youtube .qtip-content{padding:.75em;font:12px arial,sans-serif;filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#4a4a4a, EndColorStr=#000000);-ms-filter:"progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#4a4a4a, EndColorStr=#000000);"}.qtip-youtube .qtip-icon{border-color:#222}.qtip-youtube .qtip-titlebar .ui-state-hover{border-color:#303030}.qtip-jtools{background:#232323;background:rgba(0,0,0,.7);background-image:-webkit-gradient(linear,left top,left bottom,from(#717171),to(#232323));background-image:-moz-linear-gradient(top,#717171,#232323);background-image:-webkit-linear-gradient(top,#717171,#232323);background-image:-ms-linear-gradient(top,#717171,#232323);background-image:-o-linear-gradient(top,#717171,#232323);border:2px solid #ddd;border:2px solid rgba(241,241,241,1);-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 12px #333;-moz-box-shadow:0 0 12px #333;box-shadow:0 0 12px #333}.qtip-jtools .qtip-titlebar{background-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171, endColorstr=#4A4A4A);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171, endColorstr=#4A4A4A)"}.qtip-jtools .qtip-content{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A, endColorstr=#232323);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A, endColorstr=#232323)"}.qtip-jtools .qtip-titlebar,.qtip-jtools .qtip-content{background:transparent;color:#fff;border:0 dashed transparent}.qtip-jtools .qtip-icon{border-color:#555}.qtip-jtools .qtip-titlebar .ui-state-hover{border-color:#333}.qtip-cluetip{-webkit-box-shadow:4px 4px 5px rgba(0,0,0,.4);-moz-box-shadow:4px 4px 5px rgba(0,0,0,.4);box-shadow:4px 4px 5px rgba(0,0,0,.4);background-color:#D9D9C2;color:#111;border:0 dashed transparent}.qtip-cluetip .qtip-titlebar{background-color:#87876A;color:#fff;border:0 dashed transparent}.qtip-cluetip .qtip-icon{border-color:#808064}.qtip-cluetip .qtip-titlebar .ui-state-hover{border-color:#696952;color:#696952}.qtip-tipsy{background:#000;background:rgba(0,0,0,.87);color:#fff;border:0 solid transparent;font-size:11px;font-family:'Lucida Grande',sans-serif;font-weight:700;line-height:16px;text-shadow:0 1px #000}.qtip-tipsy .qtip-titlebar{padding:6px 35px 0 10px;background-color:transparent}.qtip-tipsy .qtip-content{padding:6px 10px}.qtip-tipsy .qtip-icon{border-color:#222;text-shadow:none}.qtip-tipsy .qtip-titlebar .ui-state-hover{border-color:#303030}.qtip-tipped{border:3px solid #959FA9;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;background-color:#F9F9F9;color:#454545;font-weight:400;font-family:serif}.qtip-tipped .qtip-titlebar{border-bottom-width:0;color:#fff;background:#3A79B8;background-image:-webkit-gradient(linear,left top,left bottom,from(#3A79B8),to(#2E629D));background-image:-webkit-linear-gradient(top,#3A79B8,#2E629D);background-image:-moz-linear-gradient(top,#3A79B8,#2E629D);background-image:-ms-linear-gradient(top,#3A79B8,#2E629D);background-image:-o-linear-gradient(top,#3A79B8,#2E629D);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8, endColorstr=#2E629D);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8, endColorstr=#2E629D)"}.qtip-tipped .qtip-icon{border:2px solid #285589;background:#285589}.qtip-tipped .qtip-icon .ui-icon{background-color:#FBFBFB;color:#555}.qtip-bootstrap{font-size:14px;line-height:20px;color:#333;padding:1px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.qtip-bootstrap .qtip-titlebar{padding:8px 14px;margin:0;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.qtip-bootstrap .qtip-titlebar .qtip-close{right:11px;top:45%;border-style:none}.qtip-bootstrap .qtip-content{padding:9px 14px}.qtip-bootstrap .qtip-icon{background:transparent}.qtip-bootstrap .qtip-icon .ui-icon{width:auto;height:auto;float:right;font-size:20px;font-weight:700;line-height:18px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.qtip-bootstrap .qtip-icon .ui-icon:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}.qtip:not(.ie9haxors) div.qtip-content,.qtip:not(.ie9haxors) div.qtip-titlebar{filter:none;-ms-filter:none}.qtip .qtip-tip{margin:0 auto;overflow:hidden;z-index:10}x:-o-prefocus,.qtip .qtip-tip{visibility:hidden}.qtip .qtip-tip,.qtip .qtip-tip .qtip-vml,.qtip .qtip-tip canvas{position:absolute;color:#123456;background:transparent;border:0 dashed transparent}.qtip .qtip-tip canvas{top:0;left:0}.qtip .qtip-tip .qtip-vml{behavior:url(#default#VML);display:inline-block;visibility:visible}#qtip-overlay{position:fixed;left:0;top:0;width:100%;height:100%}#qtip-overlay.blurs{cursor:pointer}#qtip-overlay div{position:absolute;left:0;top:0;width:100%;height:100%;background-color:#000;opacity:.7;filter:alpha(opacity=70);-ms-filter:"alpha(Opacity=70)"} 3 | -------------------------------------------------------------------------------- /css/loader/loader.css: -------------------------------------------------------------------------------- 1 | div.loader { 2 | width: 100px; 3 | height: 100px; 4 | position: relative; 5 | margin: auto; 6 | } 7 | 8 | .loader-bg { 9 | position: absolute; 10 | top: 0; 11 | left: 0; 12 | height: 100%; 13 | width: 100%; 14 | display: flex; 15 | justify-content: center; 16 | align-items: center; 17 | background-color: rgba(0,0,0,0.4); 18 | } 19 | 20 | .loader-bg.transparent-bg { 21 | background-color: transparent; 22 | } 23 | 24 | div.loader-card { 25 | background-color: white; 26 | display: flex; 27 | justify-content: center; 28 | align-items: center; 29 | padding: 3rem 3.75rem; 30 | padding-top: 1.75rem; 31 | border-radius: 6px; 32 | } 33 | 34 | div.loader:not(.loader-active), div.loader-bg:not(.loader-active) { 35 | display: none; 36 | } 37 | 38 | div.loader * { 39 | -webkit-box-sizing: border-box; 40 | box-sizing: border-box; 41 | margin: 0; 42 | padding: 0; 43 | } 44 | 45 | div.loader .dots { 46 | position: absolute; 47 | height: 100%; 48 | width: 100%; 49 | } 50 | 51 | div.loader .dots .dot { 52 | position: absolute; 53 | width: calc(100px / 8); 54 | height: calc(100px / 8); 55 | border-radius: 50%; 56 | background-color: #064d75; 57 | } 58 | 59 | div.loader .dots .dot-0 { 60 | opacity: 0; 61 | background-color: #064d75; 62 | left: 10px; 63 | top: 66px; 64 | -webkit-animation: dots 1.4s ease-in-out 0.1s infinite normal; 65 | animation: dots 1.4s ease-in-out 0.1s infinite normal; 66 | } 67 | 68 | div.loader .dots .dot-1 { 69 | opacity: 0; 70 | background-color: #054163; 71 | left: 20px; 72 | top: 10px; 73 | -webkit-animation: dots 1.4s ease-in-out 0.2s infinite normal; 74 | animation: dots 1.4s ease-in-out 0.2s infinite normal; 75 | } 76 | 77 | div.loader .dots .dot-2 { 78 | opacity: 0; 79 | background-color: #043652; 80 | left: 40px; 81 | top: 20px; 82 | -webkit-animation: dots 1.4s ease-in-out 0.3s infinite normal; 83 | animation: dots 1.4s ease-in-out 0.3s infinite normal; 84 | } 85 | 86 | div.loader .dots .dot-3 { 87 | opacity: 0; 88 | background-color: #032a40; 89 | left: 45px; 90 | top: 80px; 91 | -webkit-animation: dots 1.4s ease-in-out 0.4s infinite normal; 92 | animation: dots 1.4s ease-in-out 0.4s infinite normal; 93 | } 94 | 95 | div.loader .dots .dot-4 { 96 | opacity: 0; 97 | background-color: #021f2f; 98 | left: 66px; 99 | top: 25px; 100 | -webkit-animation: dots 1.4s ease-in-out 0.5s infinite normal; 101 | animation: dots 1.4s ease-in-out 0.5s infinite normal; 102 | } 103 | 104 | div.loader .dots .dot-5 { 105 | opacity: 0; 106 | background-color: #02131d; 107 | left: 55px; 108 | top: 50px; 109 | -webkit-animation: dots 1.4s ease-in-out 0.6s infinite normal; 110 | animation: dots 1.4s ease-in-out 0.6s infinite normal; 111 | } 112 | 113 | div.loader .dots .dot-6 { 114 | opacity: 0; 115 | background-color: #51829e; 116 | left: 70px; 117 | top: 70px; 118 | -webkit-animation: dots 1.4s ease-in-out 0.7s infinite normal; 119 | animation: dots 1.4s ease-in-out 0.7s infinite normal; 120 | } 121 | 122 | div.loader .dots .dot-7 { 123 | opacity: 0; 124 | background-color: #769db3; 125 | left: 80px; 126 | top: 20px; 127 | -webkit-animation: dots 1.4s ease-in-out 0.8s infinite normal; 128 | animation: dots 1.4s ease-in-out 0.8s infinite normal; 129 | } 130 | 131 | div.loader .dots .dot-8 { 132 | opacity: 0; 133 | background-color: #9bb8c8; 134 | left: 30px; 135 | top: 40px; 136 | -webkit-animation: dots 1.4s ease-in-out 0.9s infinite normal; 137 | animation: dots 1.4s ease-in-out 0.9s infinite normal; 138 | } 139 | 140 | div.loader .dots .dot-9 { 141 | opacity: 0; 142 | background-color: #c1d3dd; 143 | left: 35px; 144 | top: 65px; 145 | -webkit-animation: dots 1.4s ease-in-out 1s infinite normal; 146 | animation: dots 1.4s ease-in-out 1s infinite normal; 147 | } 148 | 149 | div.loader .lens { 150 | -webkit-perspective: 500px; 151 | perspective: 500px; 152 | height: 50%; 153 | width: 50%; 154 | position: absolute; 155 | left: 50%; 156 | top: 50%; 157 | -webkit-transform: translate(-50%, -50%); 158 | transform: translate(-50%, -50%); 159 | -webkit-transform-origin: center; 160 | transform-origin: center; 161 | } 162 | 163 | div.loader .lens img { 164 | -webkit-animation: loader 1.4s alternate ease-in-out infinite; 165 | animation: loader 1.4s alternate ease-in-out infinite; 166 | background: none; 167 | width: auto; 168 | height: auto; 169 | } 170 | 171 | div.loader .load-text { 172 | position: absolute; 173 | top: 100px; 174 | width: 100%; 175 | margin: 1rem auto; 176 | text-align: center; 177 | } 178 | div.loader .load-text>p { 179 | background: none; 180 | background-color: transparent; 181 | } 182 | 183 | @-webkit-keyframes loader { 184 | 0% { 185 | -webkit-transform: rotateY(-35deg) rotateZ(-70deg) translateZ(100px); 186 | transform: rotateY(-35deg) rotateZ(-70deg) translateZ(100px); 187 | } 188 | 100% { 189 | -webkit-transform: rotateY(35deg) rotateZ(-30deg) translateZ(100px); 190 | transform: rotateY(35deg) rotateZ(-30deg) translateZ(100px); 191 | } 192 | } 193 | 194 | @keyframes loader { 195 | 0% { 196 | -webkit-transform: rotateY(-35deg) rotateZ(-70deg) translateZ(100px); 197 | transform: rotateY(-35deg) rotateZ(-70deg) translateZ(100px); 198 | } 199 | 100% { 200 | -webkit-transform: rotateY(35deg) rotateZ(-30deg) translateZ(100px); 201 | transform: rotateY(35deg) rotateZ(-30deg) translateZ(100px); 202 | } 203 | } 204 | 205 | @-webkit-keyframes dots { 206 | from { 207 | opacity: 0; 208 | } 209 | 10% { 210 | opacity: 1; 211 | } 212 | 20% { 213 | opacity: 0; 214 | } 215 | to { 216 | opacity: 0; 217 | } 218 | } 219 | 220 | @keyframes dots { 221 | from { 222 | opacity: 0; 223 | } 224 | 10% { 225 | opacity: 1; 226 | } 227 | 20% { 228 | opacity: 0; 229 | } 230 | to { 231 | opacity: 0; 232 | } 233 | } 234 | /*# sourceMappingURL=loader.css.map */ -------------------------------------------------------------------------------- /css/loader/loader.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "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", 4 | "sources": [ 5 | "loader.scss" 6 | ], 7 | "names": [], 8 | "file": "loader.css" 9 | } -------------------------------------------------------------------------------- /css/loader/loader.scss: -------------------------------------------------------------------------------- 1 | $size: 100px; 2 | $blue: rgb(6, 77, 117); 3 | $animation-length: 1.4s; 4 | $dots: ( 5 | "0": ( 6 | "x": 10 / 100 * $size, 7 | "y": 66 / 100 * $size, 8 | ), 9 | "1": ( 10 | "x": 20/ 100 * $size, 11 | "y": 10/ 100 * $size, 12 | ), 13 | "2": ( 14 | "x": 40/ 100 * $size, 15 | "y": 20/ 100 * $size, 16 | ), 17 | "3": ( 18 | "x": 45/ 100 * $size, 19 | "y": 80/ 100 * $size, 20 | ), 21 | "4": ( 22 | "x": 66/ 100 * $size, 23 | "y": 25/ 100 * $size, 24 | ), 25 | "5": ( 26 | "x": 55/ 100 * $size, 27 | "y": 50/ 100 * $size, 28 | ), 29 | "6": ( 30 | "x": 70/ 100 * $size, 31 | "y": 70/ 100 * $size, 32 | ), 33 | "7": ( 34 | "x": 80/ 100 * $size, 35 | "y": 20/ 100 * $size, 36 | ), 37 | "8": ( 38 | "x": 30/ 100 * $size, 39 | "y": 40/ 100 * $size, 40 | ), 41 | "9": ( 42 | "x": 35/ 100 * $size, 43 | "y": 65/ 100 * $size, 44 | ), 45 | ); 46 | div.loader { 47 | &:not(.loader-active) { 48 | display: none; 49 | } 50 | * { 51 | box-sizing: border-box; 52 | margin: 0; 53 | padding: 0; 54 | } 55 | width: $size; 56 | height: $size; 57 | position: relative; 58 | margin: auto; 59 | .dots { 60 | position: absolute; 61 | height: 100%; 62 | width: 100%; 63 | .dot { 64 | position: absolute; 65 | width: calc(#{$size} / 8); 66 | height: calc(#{$size} / 8); 67 | border-radius: 50%; 68 | background-color: $blue; 69 | } 70 | @each $x, $val in $dots { 71 | $index: index($dots, $x $val); 72 | .dot-#{$x} { 73 | opacity: 0; 74 | @if $index > 0 and $index < 7 { 75 | background-color: mix(black, $blue, ($index - 1) * 15); 76 | } @else if $index >= 7 { 77 | background-color: mix(white, $blue, ($index - 5) * 15); 78 | } 79 | left: map-get($val, $key: "x"); 80 | top: map-get($val, $key: "y"); 81 | animation: dots 82 | $animation-length 83 | ease-in-out 84 | ($index * $animation-length / 14) 85 | infinite 86 | normal; 87 | } 88 | } 89 | } 90 | .lens { 91 | perspective: $size * 5; 92 | height: 50%; 93 | width: 50%; 94 | position: absolute; 95 | left: 50%; 96 | top: 50%; 97 | transform: translate(-50%, -50%); 98 | transform-origin: center; 99 | img { 100 | animation: loader $animation-length alternate ease-in-out infinite; 101 | background: none; 102 | width: auto; 103 | height: auto; 104 | } 105 | } 106 | .load-text { 107 | position: absolute; 108 | top: $size; 109 | width: 100%; 110 | margin: 1rem auto; 111 | text-align: center; 112 | } 113 | } 114 | @keyframes loader { 115 | 0% { 116 | transform: rotateY(-35deg) rotateZ(-70deg) translateZ($size); 117 | } 118 | 100% { 119 | transform: rotateY(35deg) rotateZ(-30deg) translateZ($size); 120 | } 121 | } 122 | 123 | @keyframes dots { 124 | from { 125 | opacity: 0; 126 | } 127 | 10% { 128 | opacity: 1; 129 | } 130 | 20% { 131 | opacity: 0; 132 | } 133 | to { 134 | opacity: 0; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /css/options.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background: #fafafa; 3 | font-family: Helvetica; 4 | } 5 | table, td { 6 | border: 1px solid black; 7 | } 8 | #userList{ 9 | display: inline-block; 10 | border: 2.5px solid #1a509d; 11 | } 12 | #trustedList{ 13 | float: left; 14 | margin-right: 10px; 15 | border: 2.5px solid green; 16 | } 17 | #timerInput{ 18 | margin-right: 5px; 19 | margin-left: 5px; 20 | } 21 | #trustedListText{ 22 | font-weight: bold; 23 | } 24 | #userListText,#referrerHeadline{ 25 | font-weight: bold; 26 | margin-top: 25px; 27 | } 28 | #optionButtons{ 29 | margin-top: 10px; 30 | } 31 | #userDefinedInput, #referrerInput{ 32 | width: 400px; 33 | } 34 | #addDefaultReferrer{ 35 | margin-bottom: 5px; 36 | text-decoration: none; 37 | } 38 | #addDefaultReferrer:hover:enabled{ 39 | text-decoration: underline; 40 | } 41 | .left{ 42 | float: left; 43 | } 44 | .right{ 45 | padding:4px; 46 | } 47 | .last{ 48 | padding:10px; 49 | } 50 | .clear{ 51 | clear: left; 52 | } 53 | 54 | /*----- Tabs -----*/ 55 | .tabs { 56 | width:100%; 57 | display:inline-block; 58 | } 59 | 60 | /*----- Tab Links -----*/ 61 | .tab-links{ 62 | margin: 0; 63 | padding: 0; 64 | } 65 | /* Clearfix */ 66 | .tab-links:after { 67 | display:block; 68 | clear:both; 69 | content:''; 70 | } 71 | 72 | .tab-links li { 73 | margin:0px 5px 0px 0px; 74 | float:left; 75 | list-style:none; 76 | } 77 | 78 | .tab-links a { 79 | padding:9px 15px; 80 | display:inline-block; 81 | border-radius:3px 3px 0px 0px; 82 | background:#d9d9d9; 83 | font-size:16px; 84 | font-weight:600; 85 | color:#4c4c4c; 86 | transition:all linear 0.15s; 87 | } 88 | 89 | .tab-links a:hover { 90 | background:#a7cce5; 91 | text-decoration:none; 92 | } 93 | 94 | li.active a, li.active a:hover { 95 | background:#a7cce5; 96 | color:#4c4c4c; 97 | } 98 | 99 | /*----- Content of Tabs -----*/ 100 | .tab-content { 101 | padding:15px; 102 | border-radius:3px; 103 | box-shadow:-1px 1px 1px rgba(0,0,0,0.15); 104 | background: #f2f2f2; 105 | border:1px solid #999; 106 | } 107 | .tab { 108 | display:none; 109 | } 110 | .tab.active { 111 | display:block; 112 | } 113 | .tab > div{ 114 | margin: 10px 5px 15px 5px; 115 | } 116 | -------------------------------------------------------------------------------- /css/tooltip.css: -------------------------------------------------------------------------------- 1 | .torpedoTooltip { 2 | border: solid 0.3rem #bfb9b9; 3 | border-radius: 5px; 4 | background-color: white; 5 | min-width: 430px; 6 | font-size: 14px !important; 7 | font-family: Helvetica !important; 8 | line-height: 130% !important; 9 | } 10 | 11 | #torpedoContextMenu { 12 | border: 0.1rem solid #bfb9b9; 13 | background-color: white; 14 | font-size: 14px !important; 15 | font-family: Helvetica !important; 16 | line-height: 130% !important; 17 | } 18 | 19 | #torpedoContextMenu ul { 20 | padding: 5px; 21 | list-style: none; 22 | margin: 0; 23 | } 24 | #torpedoContextMenu li { 25 | list-style: none; 26 | padding: 0 10px 0 10px; 27 | margin: 1px 0 1px 0; 28 | background-color: white; 29 | color: black; 30 | } 31 | #torpedoContextMenu li:hover { 32 | background-color: #cce0ff; 33 | } 34 | .qtip-content { 35 | background-color: white !important; 36 | min-height: 100px; 37 | position: relative; 38 | } 39 | div.torpedoTooltip div.torpedoTooltip div, 40 | div.torpedoTooltip span, 41 | div.torpedoTooltip applet, 42 | div.torpedoTooltip object, 43 | div.torpedoTooltip iframe, 44 | div.torpedoTooltip h1, 45 | div.torpedoTooltip h2, 46 | div.torpedoTooltip h3, 47 | div.torpedoTooltip h4, 48 | div.torpedoTooltip h5, 49 | div.torpedoTooltip h6, 50 | div.torpedoTooltip p, 51 | div.torpedoTooltip blockquote, 52 | div.torpedoTooltip pre, 53 | div.torpedoTooltip a, 54 | div.torpedoTooltip abbr, 55 | div.torpedoTooltip acronym, 56 | div.torpedoTooltip address, 57 | div.torpedoTooltip big, 58 | div.torpedoTooltip cite, 59 | div.torpedoTooltip code, 60 | div.torpedoTooltip del, 61 | div.torpedoTooltip dfn, 62 | div.torpedoTooltip em, 63 | div.torpedoTooltip img, 64 | div.torpedoTooltip ins, 65 | div.torpedoTooltip kbd, 66 | div.torpedoTooltip q, 67 | div.torpedoTooltip s, 68 | div.torpedoTooltip samp, 69 | div.torpedoTooltip small, 70 | div.torpedoTooltip strike, 71 | div.torpedoTooltip strong, 72 | div.torpedoTooltip sub, 73 | div.torpedoTooltip sup, 74 | div.torpedoTooltip tt, 75 | div.torpedoTooltip var, 76 | div.torpedoTooltip b, 77 | div.torpedoTooltip u, 78 | div.torpedoTooltip i, 79 | div.torpedoTooltip center, 80 | div.torpedoTooltip dl, 81 | div.torpedoTooltip dt, 82 | div.torpedoTooltip dd, 83 | div.torpedoTooltip ol, 84 | div.torpedoTooltip ul, 85 | div.torpedoTooltip li, 86 | div.torpedoTooltip fieldset, 87 | div.torpedoTooltip form, 88 | div.torpedoTooltip label, 89 | div.torpedoTooltip legend, 90 | div.torpedoTooltip table, 91 | div.torpedoTooltip caption, 92 | div.torpedoTooltip tbody, 93 | div.torpedoTooltip tfoot, 94 | div.torpedoTooltip thead, 95 | div.torpedoTooltip tr, 96 | div.torpedoTooltip th, 97 | div.torpedoTooltip td, 98 | div.torpedoTooltip article, 99 | div.torpedoTooltip aside, 100 | div.torpedoTooltip canvas, 101 | div.torpedoTooltip details, 102 | div.torpedoTooltip embed, 103 | div.torpedoTooltip figure, 104 | div.torpedoTooltip figcaption, 105 | div.torpedoTooltip footer, 106 | div.torpedoTooltip header, 107 | div.torpedoTooltip hgroup, 108 | div.torpedoTooltip menu, 109 | div.torpedoTooltip nav, 110 | div.torpedoTooltip output, 111 | div.torpedoTooltip ruby, 112 | div.torpedoTooltip section, 113 | div.torpedoTooltip summary, 114 | div.torpedoTooltip time, 115 | div.torpedoTooltip mark, 116 | div.torpedoTooltip audio, 117 | div.torpedoTooltip video { 118 | margin: 0; 119 | padding: 0; 120 | border: 0; 121 | font-size: 100%; 122 | background-color: white; 123 | font: inherit; 124 | vertical-align: baseline; 125 | } 126 | div.torpedoTooltip .loader-active:not(.loader):not(.loader-bg) { 127 | display: none; 128 | } 129 | 130 | /* HTML5 display-role reset for older browsers */ 131 | article, 132 | div.torpedoTooltip aside, 133 | div.torpedoTooltip details, 134 | div.torpedoTooltip figcaption, 135 | div.torpedoTooltip figure, 136 | div.torpedoTooltip footer, 137 | div.torpedoTooltip header, 138 | div.torpedoTooltip hgroup, 139 | div.torpedoTooltip menu, 140 | div.torpedoTooltip nav, 141 | div.torpedoTooltip section { 142 | display: block; 143 | } 144 | 145 | div.torpedoTooltip ol, 146 | div.torpedoTooltip ul { 147 | list-style: none; 148 | } 149 | div.torpedoTooltip blockquote, 150 | div.torpedoTooltip q { 151 | quotes: none; 152 | } 153 | div.torpedoTooltip blockquote:before, 154 | div.torpedoTooltip blockquote:after, 155 | div.torpedoTooltip q:before, 156 | div.torpedoTooltip q:after { 157 | content: ""; 158 | content: none; 159 | } 160 | div.torpedoTooltip table { 161 | border-collapse: collapse; 162 | border-spacing: 0; 163 | } 164 | 165 | .torpedoPopup { 166 | max-width: none !important; 167 | background-color: white; 168 | border: 2px solid black; 169 | } 170 | .torpedoTooltip div { 171 | padding-bottom: 10px; 172 | } 173 | .torpedoTooltip p { 174 | overflow: hidden !important; 175 | color: black !important; 176 | } 177 | .torpedoTooltip img { 178 | float: left; 179 | width: 25px; 180 | height: 25px; 181 | padding-right: 10px; 182 | padding-bottom: 10px; 183 | margin-bottom: 5px; 184 | } 185 | .torpedoTooltip .torpedoHighlight, 186 | .torpedoHighlight { 187 | font-weight: bold; 188 | display: inline; 189 | margin-bottom: 0px !important; 190 | margin-right: 2px; 191 | } 192 | .torpedoTrusted { 193 | border: 0.3rem solid green !important; 194 | } 195 | .torpedoUserDefined { 196 | border: 0.3rem solid #1a509d !important; 197 | } 198 | 199 | .torpedoPhish { 200 | border: 0.3rem solid red !important; 201 | } 202 | 203 | #torpedoDomain { 204 | font-weight: bold !important; 205 | letter-spacing: 3px !important; 206 | margin: 10px 2px 25px 2px; 207 | } 208 | #torpedoInfoImage, 209 | #torpedoAdviceImage, 210 | #torpedoWarningImage { 211 | padding-right: 10px; 212 | } 213 | 214 | #torpedoAdviceText { 215 | text-decoration: underline; 216 | cursor: pointer; 217 | font-weight: normal; 218 | } 219 | 220 | #torpedoAdviceText:hover { 221 | font-weight: bold; 222 | cursor: pointer; 223 | } 224 | 225 | #torpedoInfoText { 226 | text-decoration: underline; 227 | cursor: help; 228 | font-weight: normal; 229 | } 230 | #torpedoInfoText:hover { 231 | font-weight: bold; 232 | cursor: pointer; 233 | } 234 | #torpedoInfoDiv { 235 | overflow-y: scroll; 236 | height: 90px; 237 | } 238 | #torpedoInfoDiv, 239 | #torpedoLinkDelay, 240 | #torpedoURL, 241 | #torpedoMoreInfoButton, 242 | #torpedoRedirectButton, 243 | #torpedoActivateLinkButton { 244 | clear: both; 245 | width: 100%; 246 | margin-top: 5px; 247 | } 248 | #torpedoPopupImage { 249 | width: 600px; 250 | height: 380px; 251 | } 252 | #torpedoMoreInfoButton { 253 | margin: 10px 0 0 10px; 254 | } 255 | #torpedoURL { 256 | color: black !important; 257 | word-wrap: break-word; 258 | word-break: break-all; 259 | margin-bottom: 13px; 260 | text-decoration: none; 261 | } 262 | #torpedoSecurityStatus { 263 | margin-top: 5px; 264 | } 265 | #torpedoInfo, 266 | #torpedoAdvice { 267 | padding-bottom: 5px; 268 | } 269 | -------------------------------------------------------------------------------- /css/tutorial/tutorial.css.backup: -------------------------------------------------------------------------------- 1 | body 2 | { 3 | background-color: #eeeeee; 4 | margin-left: auto; 5 | margin-right: auto; 6 | margin-top: 0px; 7 | text-align: center; 8 | overflow: auto; 9 | } 10 | 11 | #finish{ 12 | float: right; 13 | } 14 | 15 | button{border:none;display:inline-block;outline:0;padding:8px 16px;vertical-align:middle;overflow:hidden;text-decoration:none;color:inherit;background-color:inherit;text-align:center;cursor:pointer;white-space:nowrap} 16 | button{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} 17 | button:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none} 18 | button:hover{color:#000!important;background-color:#ccc!important} 19 | -------------------------------------------------------------------------------- /css/tutorial/tutorial.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "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", 4 | "sources": [ 5 | "tutorial.scss" 6 | ], 7 | "names": [], 8 | "file": "tutorial.css" 9 | } -------------------------------------------------------------------------------- /css/tutorial/tutorial.scss: -------------------------------------------------------------------------------- 1 | // VARIABLES 2 | $torpedo-grey: #bfb9b9; 3 | $torpedo-green: green; 4 | $torpedo-blue: #1a509d; 5 | $torpedo-red: red; 6 | $size-overview: 3vw; 7 | // bubble dark colors for radial gradient need to be adapted at the place in code 8 | 9 | // MIXINS 10 | @mixin flex($justify, $align, $flex-direction) { 11 | display: flex; 12 | justify-content: $justify; 13 | align-items: $align; 14 | flex-direction: $flex-direction; 15 | } 16 | 17 | * { 18 | margin: 0; 19 | padding: 0; 20 | box-sizing: border-box; 21 | } 22 | html { 23 | font-size: 62.5%; 24 | } 25 | body { 26 | font-size: 2rem; 27 | background-image: linear-gradient( 28 | to bottom right, 29 | rgb(255, 255, 255), 30 | rgb(245, 245, 245) 20%, 31 | rgb(201, 201, 201) 32 | ); 33 | } 34 | h2 { 35 | font-size: 4rem; 36 | margin: 2rem 1rem 3rem 1rem; 37 | } 38 | h3 { 39 | font-size: 2.5rem; 40 | margin: 2rem 1rem; 41 | } 42 | h4 { 43 | font-size: 2rem; 44 | margin: 1.5rem 1rem; 45 | } 46 | p { 47 | margin: 1rem 1rem 2rem 1rem; 48 | } 49 | ol { 50 | margin: 1rem inherit; 51 | } 52 | li { 53 | padding: 1rem 0; 54 | } 55 | 56 | .fat { 57 | font-weight: bold; 58 | } 59 | .italic { 60 | font-style: italic; 61 | } 62 | .underlined { 63 | text-decoration: underline; 64 | } 65 | .link-like { 66 | color: blue; 67 | text-decoration: underline; 68 | } 69 | .green { 70 | color: $torpedo-green; 71 | } 72 | .grey { 73 | color: $torpedo-grey; 74 | } 75 | .blue { 76 | color: $torpedo-blue; 77 | } 78 | .red { 79 | color: $torpedo-red; 80 | } 81 | 82 | // OVERVIEW 83 | header { 84 | position: sticky; 85 | top: 0; 86 | height: 17vh; 87 | background-color: white; 88 | border-radius: 0 0 20px 20px; 89 | box-shadow: 0 0.5rem 2rem rgba(0, 0, 0, 0.383), 90 | 0 0.2rem 1rem rgba(0, 0, 0, 0.4); 91 | } 92 | .header-wrapper { 93 | width: 85%; 94 | height: 100%; 95 | margin: auto; 96 | @include flex(space-between, center, row); 97 | } 98 | #torpedo-title { 99 | width: 15vw; 100 | } 101 | .torpedo-title-wrapper { 102 | margin-right: auto; 103 | } 104 | .overview { 105 | @include flex(space-between, center, row); 106 | // display none will be removed as soon as within examples 107 | display: none; 108 | width: 60%; 109 | .overview-case { 110 | opacity: 0.4; 111 | height: $size-overview; 112 | width: $size-overview; 113 | border-radius: 60%; 114 | flex-shrink: 0; 115 | @include flex(center, center, row); 116 | cursor: pointer; 117 | transition: all 0.2s ease; 118 | box-shadow: 0 0.25rem 1rem rgba(121, 93, 93, 0.383), 119 | 0 0.1rem 0.5rem rgba(0, 0, 0, 0.4); 120 | &:hover { 121 | // box-shadow: 0 0 1rem $torpedo-blue; 122 | box-shadow: 0 0 1rem $torpedo-blue; 123 | opacity: 0.9; 124 | } 125 | } 126 | .angled { 127 | transform: rotateZ(25deg); 128 | } 129 | .fas { 130 | font-size: calc(#{$size-overview} / 2); 131 | } 132 | .selected { 133 | opacity: 1; 134 | } 135 | .not-colored { 136 | background-image: radial-gradient( 137 | circle at 35% 35%, 138 | white, 139 | hsl(0, 0%, 75%) 140 | ); 141 | } 142 | 143 | .welcome { 144 | border: torpedo; 145 | } 146 | .green-case { 147 | background-image: radial-gradient( 148 | circle at 35% 35%, 149 | $torpedo-green, 150 | hsl(120, 100%, 12%) 151 | ); 152 | background-color: $torpedo-green; 153 | } 154 | .blue-case { 155 | background-image: radial-gradient( 156 | circle at 35% 35%, 157 | $torpedo-blue, 158 | hsl(215, 72%, 18%) 159 | ); 160 | background-color: $torpedo-blue; 161 | } 162 | .simple-grey-case-no-phish, 163 | .simple-grey-case-phish, 164 | .warning-grey-case-no-phish, 165 | .warning-grey-case-phish { 166 | background-image: radial-gradient( 167 | circle at 35% 35%, 168 | $torpedo-grey, 169 | hsl(0, 4%, 40%) 170 | ); 171 | background-color: $torpedo-grey; 172 | } 173 | .warning-grey-case-no-phish, 174 | .warning-grey-case-phish { 175 | background-image: url("../../img/warning2.png"), 176 | radial-gradient(circle at 35% 35%, $torpedo-grey, hsl(0, 4%, 40%)); 177 | background-size: 50%, 100%; 178 | background-position: 50% 50%; 179 | background-repeat: no-repeat; 180 | } 181 | .red-case { 182 | background-image: radial-gradient( 183 | circle at 35% 35%, 184 | $torpedo-red, 185 | hsl(0, 100%, 25%) 186 | ); 187 | background-color: $torpedo-red; 188 | } 189 | } 190 | 191 | // CONTENT TUTORIAL 192 | // introduction 193 | .card { 194 | background-color: white; 195 | width: 100%; 196 | padding: 2rem 5rem; 197 | border-radius: 20px; 198 | box-shadow: 0.5rem 0.5rem 2rem rgba(0, 0, 0, 0.2), 199 | 0.5rem 0.5rem 2rem rgba(0, 0, 0, 0.4); 200 | &.card-append { 201 | margin-bottom: 3rem; 202 | } 203 | } 204 | 205 | .explanation { 206 | .domain-mark { 207 | font-weight: bold; 208 | letter-spacing: 0.2rem; 209 | background-color: yellow; 210 | border-radius: 0.2rem; 211 | padding: 0.2rem; 212 | } 213 | } 214 | .explanation-summary-cases { 215 | margin-top: 4rem; 216 | margin-right: -2rem; 217 | margin-left: -2rem; 218 | @include flex(space-between, stretch, row); 219 | flex-wrap: wrap; 220 | & > * { 221 | flex: 1 1 60rem; 222 | } 223 | .show-case-card { 224 | margin: 2rem; 225 | cursor: pointer; 226 | } 227 | .showcase-title { 228 | text-align: center; 229 | font-size: 2.5rem; 230 | margin: 2rem; 231 | margin-bottom: 4rem; 232 | } 233 | .case-img-summary { 234 | margin: auto; 235 | } 236 | } 237 | // examples in tutorial 238 | .tut-content-wrapper { 239 | min-height: 83vh; 240 | padding: 6rem 0 12rem 0; 241 | @include flex(center, center, row); 242 | } 243 | .tut-content { 244 | margin: auto; 245 | width: 85%; 246 | } 247 | .example-wrapper { 248 | margin: auto -3rem; 249 | @include flex(space-between, flex-end, row); 250 | flex-direction: row-reverse; 251 | flex-wrap: wrap; 252 | } 253 | .example-explain-title { 254 | text-align: center; 255 | } 256 | .example-svg { 257 | order: 2; 258 | flex: 1 1 40rem; 259 | margin: 5rem 3rem; 260 | } 261 | .explanation-card { 262 | order: 1; 263 | flex: 2 2 70rem; 264 | margin: auto 3rem; 265 | } 266 | .visual-seperator { 267 | background-image: linear-gradient( 268 | to right, 269 | white 0%, 270 | $torpedo-grey 15%, 271 | $torpedo-grey 85%, 272 | white 100% 273 | ); 274 | width: 60%; 275 | margin: 3rem auto; 276 | border: none; 277 | height: 2px; 278 | } 279 | 280 | // CONFUGARTIONS 281 | $flex-gap-contextmenu: 3rem; 282 | 283 | .special-cases-wrapper { 284 | margin-left: -$flex-gap-contextmenu; 285 | margin-right: -$flex-gap-contextmenu; 286 | @include flex(space-between, center, row-reverse); 287 | flex-wrap: wrap; 288 | } 289 | .special-cases-img { 290 | order: 2; 291 | #contextmenu-img { 292 | width: 100%; 293 | } 294 | flex: 1 1 40rem; 295 | margin: 2rem $flex-gap-contextmenu; 296 | } 297 | .special-cases-explanation { 298 | order: 1; 299 | flex: 1.5 1 70rem; 300 | margin: 2rem $flex-gap-contextmenu; 301 | } 302 | .settings-wrapper { 303 | @include flex(space-between, center, row); 304 | flex-wrap: wrap; 305 | margin-left: -$flex-gap-contextmenu; 306 | margin-right: -$flex-gap-contextmenu; 307 | } 308 | .settings-explanation { 309 | margin: 2rem $flex-gap-contextmenu; 310 | flex: 2 1 70rem; 311 | ol { 312 | padding-left: 3rem; 313 | } 314 | } 315 | .settings-img-wrapper { 316 | margin: 2rem $flex-gap-contextmenu; 317 | flex: 1 1 50rem; 318 | @include flex(center, center, row); 319 | } 320 | 321 | // NAV-BUTTONS 322 | .navigation-btns { 323 | position: fixed; 324 | bottom: 0; 325 | left: 50%; 326 | transform: translateX(-50%); 327 | width: 30%; 328 | min-width: 30rem; 329 | margin: 3rem auto; 330 | @include flex(space-around, center, row); 331 | button { 332 | display: block; 333 | padding: 2rem 2rem; 334 | background-color: $torpedo-blue; 335 | border: none; 336 | border-radius: 100%; 337 | cursor: pointer; 338 | font-size: 2rem; 339 | color: white; 340 | } 341 | .disabled { 342 | background-color: $torpedo-blue; 343 | filter: saturate(30%); 344 | cursor: default; 345 | &:hover { 346 | animation: denied 250ms forwards ease; 347 | } 348 | > * { 349 | pointer-events: none; 350 | } 351 | @keyframes denied { 352 | 0% { 353 | transform: translateX(0); 354 | } 355 | 15% { 356 | transform: translateX(1rem); 357 | } 358 | 35% { 359 | transform: translateX(-1rem); 360 | } 361 | 55% { 362 | transform: translateX(1rem); 363 | } 364 | 80% { 365 | transform: translateX(-1rem); 366 | } 367 | 100% { 368 | transform: translateX(0); 369 | } 370 | } 371 | } 372 | .square-div { 373 | height: 2rem; 374 | width: 2rem; 375 | @include flex(center, center, row); 376 | } 377 | } 378 | 379 | .off { 380 | display: none !important; 381 | } 382 | 383 | @media (min-width: 2200px) { 384 | .explanation-summary-cases { 385 | & > * { 386 | flex: 1 1 40rem; 387 | } 388 | } 389 | } 390 | -------------------------------------------------------------------------------- /icon.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /img/TORPEDO_Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /img/TORPEDO_fullLockup.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /img/advice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecUSo/torpedo/422ebdc5124e248b3e8939b0324d3a60b683fa5d/img/advice.png -------------------------------------------------------------------------------- /img/error38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecUSo/torpedo/422ebdc5124e248b3e8939b0324d3a60b683fa5d/img/error38.png -------------------------------------------------------------------------------- /img/error64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecUSo/torpedo/422ebdc5124e248b3e8939b0324d3a60b683fa5d/img/error64.png -------------------------------------------------------------------------------- /img/examples/de/blue_case_de.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | https://www.paypal.com/de/home 12 | 13 | 14 | 15 | 16 | https://www 17 | . 18 | paypal.com 19 | /de/home 20 | 21 | 22 | Hinterlegte URL (auch Webadresse genannt): 23 | 24 | 25 | Geringes Risiko: Das Risiko für das Klicken auf den Link wird 26 | aufgrund Ihren früheren Angaben zur Vertrauenswürdigkeit der 27 | Domain ( 28 | fett hervorgehobene Bereich 29 | ) als gering eingestuft. 30 | 31 | 32 | 33 | Mehr Informationen zu dieser Einstufung 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /img/examples/de/green_case_de.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | https://www 13 | . 14 | ebay.de 15 | / 16 | 17 | 18 | Hinterlegte URL (auch Webadresse genannt): 19 | 20 | 21 | Geringes Risiko: Das Risiko für das Klicken auf den Link wird 22 | aufgrund der bekannten Vertrauenswürdigkeit der Domain ( 23 | fett 24 | hervorgehobene Bereich der URL 25 | ) als gering eingestuft. 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Hier klicken 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | Mehr Informationen zu dieser Einstufung 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /img/examples/de/settings_de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecUSo/torpedo/422ebdc5124e248b3e8939b0324d3a60b683fa5d/img/examples/de/settings_de.png -------------------------------------------------------------------------------- /img/examples/de/simple-grey_case_no-phish_de.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | https://www 13 | . 14 | rwth-aachen.de 15 | /cms/~a/root/lidx/1 16 | 17 | 18 | Hinterlegte URL (auch Webadresse genannt): 19 | 20 | 21 | Unbekanntes Risiko: 22 | Das Risiko für das Klicken auf den Link 23 | kann nicht bestimmt werden. Sie müssen hier das Risiko selbst 24 | einstufen. Hierzu prüfen Sie die Domain 25 | ( 26 | fett hervorgehobener Bereich 27 | ). 28 | 29 | 30 | Der Link wurde deaktiviert, damit Sie die Domain in Ruhe prüfen. 31 | 32 | 33 | Verbleibende Zeit: 2 Sekunde(n). 34 | 35 | 36 | 37 | Mehr Informationen zu dieser Einstufung 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | https://www.rwth-aachen.de/cms/~a/root/lidx/1 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /img/examples/de/simple-grey_case_phish_de.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | https:/ 13 | / 14 | 2020coronaviruspandemic.com 15 | / 16 | 17 | 18 | Hinterlegte URL (auch Webadresse genannt): 19 | 20 | 21 | Unbekanntes Risiko: 22 | Das Risiko für das Klicken auf den Link 23 | kann nicht bestimmt werden. Sie müssen hier das Risiko selbst 24 | einstufen. Hierzu prüfen Sie die Domain 25 | ( 26 | fett hervorgehobener Bereich 27 | ). 28 | 29 | 30 | Der Link wurde deaktiviert, damit Sie die Domain in Ruhe prüfen. 31 | 32 | 33 | Verbleibende Zeit: 2 Sekunde(n). 34 | 35 | 36 | 37 | Mehr Informationen zu dieser Einstufung 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | Hier 57 | finden Sie 58 | mehr Information 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /img/examples/en/blue_case_en.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | https://www.paypal.com/de/home 12 | 13 | 14 | 15 | 16 | https://www 17 | . 18 | paypal.com 19 | /de/home 20 | 21 | 22 | Deposited URL (also called web address): 23 | 24 | 25 | Low risk: The risk of clicking this link is considered to be low 26 | because of your previous statements concerning the 27 | trustworthiness of the domain ( 28 | bold area 29 | ) of this URL. 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | More information on this classification 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /img/examples/en/green_case_en.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | https://www 13 | . 14 | ebay.de 15 | / 16 | 17 | 18 | Deposited URL (also called web address): 19 | 20 | 21 | Low risk: the risk of clicking the link is considered to be low 22 | because of the trustworthiness of the domain ( 23 | bold area 24 | ) 25 | of this URL. 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | More information on this classification 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | Click here 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /img/examples/en/settings_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecUSo/torpedo/422ebdc5124e248b3e8939b0324d3a60b683fa5d/img/examples/en/settings_en.png -------------------------------------------------------------------------------- /img/examples/en/simple-grey_case_no-phish_en.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | https://www 13 | . 14 | youtube.com 15 | /feed/subscriptions 16 | 17 | 18 | Desposited URL (also called web address): 19 | 20 | 21 | Unknown risk: 22 | The risk of clicking this link can not definitively 23 | be classified. You have to classify the risk yourself by checking 24 | the domain ( 25 | bold area 26 | ) of the URL. 27 | 28 | 29 | The link was deactivated to give you time to check the domain. 30 | 31 | 32 | Remaining time: 2 second(s). 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | More information on this classification 50 | 51 | 52 | 53 | 54 | 55 | https://www.youtube.com/feed/subscriptions 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /img/examples/en/simple-grey_case_phish_en.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | https:/ 13 | / 14 | 2020coronaviruspandemic.com 15 | / 16 | 17 | 18 | Deposited URL (also called web address): 19 | 20 | 21 | Unknown risk: 22 | The risk of clicking this link can not definitively 23 | be classified. You have to classify the risk yourself by checking 24 | the domain ( 25 | bold area 26 | ) of the URL. 27 | 28 | 29 | The link was deactivated to give you time to check the domain. 30 | 31 | 32 | Remaining time: 2 second(s). 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | More information on this classification 50 | 51 | 52 | 53 | 54 | 55 | Here 56 | are further 57 | details about it. 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /img/icon38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecUSo/torpedo/422ebdc5124e248b3e8939b0324d3a60b683fa5d/img/icon38.png -------------------------------------------------------------------------------- /img/icon64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecUSo/torpedo/422ebdc5124e248b3e8939b0324d3a60b683fa5d/img/icon64.png -------------------------------------------------------------------------------- /img/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecUSo/torpedo/422ebdc5124e248b3e8939b0324d3a60b683fa5d/img/info.png -------------------------------------------------------------------------------- /img/none38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecUSo/torpedo/422ebdc5124e248b3e8939b0324d3a60b683fa5d/img/none38.png -------------------------------------------------------------------------------- /img/none64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecUSo/torpedo/422ebdc5124e248b3e8939b0324d3a60b683fa5d/img/none64.png -------------------------------------------------------------------------------- /img/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecUSo/torpedo/422ebdc5124e248b3e8939b0324d3a60b683fa5d/img/warning.png -------------------------------------------------------------------------------- /img/warning2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecUSo/torpedo/422ebdc5124e248b3e8939b0324d3a60b683fa5d/img/warning2.png -------------------------------------------------------------------------------- /js/contentscript.js: -------------------------------------------------------------------------------- 1 | var torpedo = torpedo || {}; 2 | torpedo.target = null; 3 | torpedo.api = null; 4 | torpedo.uri = ""; 5 | torpedo.url = ""; 6 | torpedo.domain = ""; 7 | torpedo.pathname = ""; 8 | torpedo.publicsuffixlist = ""; 9 | torpedo.event; 10 | torpedo.location; 11 | torpedo.opened = false; 12 | torpedo.progUrl = false; 13 | torpedo.hasTooltip = false; 14 | 15 | $(document).ready(function () { 16 | chrome.runtime.sendMessage({ name: "TLD" }, function (r) { 17 | torpedo.publicSuffixList.parse(r, punycode.toASCII); 18 | }); 19 | 20 | //torpedo.location = window.location.host; 21 | torpedo.opened = false; 22 | torpedo.progUrl = false; 23 | torpedo.hasTooltip = false; 24 | 25 | $("body").unbind(); 26 | 27 | $("body").on("mouseenter", "a", function (e) { 28 | openTooltip(e, "a"); 29 | }); 30 | 31 | $("body").on("mouseenter", "form", function (e) { 32 | openTooltip(e, "form"); 33 | torpedo.progUrl = true; 34 | }); 35 | }); 36 | 37 | function openTooltip(e, type) { 38 | torpedo.target = e.currentTarget; 39 | torpedo.progUrl = false; 40 | torpedo.hasTooltip = false; 41 | 42 | const eventTypes = ["click", "contextmenu", "mouseup", "mousedown"]; 43 | 44 | // do not prevent click event on mailto links 45 | if (type == "a") { 46 | if (torpedo.target.href.indexOf("mailto:") > -1) 47 | return; 48 | } 49 | preventClickEvent(torpedo.target, eventTypes); 50 | 51 | if (type == "a") { 52 | if ( 53 | torpedo.opened || 54 | $(torpedo.target).hasClass("qtip-close") 55 | ) 56 | return; 57 | if (torpedo.target.href == "") { 58 | try { 59 | $(torpedo.target).attr("href", e.relatedTarget.href); 60 | } catch (err) { } 61 | } 62 | } 63 | 64 | torpedo.state = "unknown"; 65 | chrome.storage.sync.get(null, function (r) { 66 | try { 67 | // try to construct a URL, this will fail if it's a non-valid URL 68 | var url; 69 | if (type == "form") { 70 | url = new URL(torpedo.target.action); 71 | } else { 72 | url = new URL(torpedo.target.href); 73 | } 74 | 75 | setNewUrl(url); 76 | 77 | // checks for programmed tooltip (if there, then assigned to tooltipURL) 78 | var tooltipURL = hasTooltip(torpedo.target); 79 | 80 | if (tooltipURL != "") { 81 | torpedo.hasTooltip = isTooltipMismatch(tooltipURL, torpedo.url); 82 | } 83 | 84 | $(torpedo.target).on("mouseenter", function (event) { 85 | if (torpedo.timerInterval != null) { 86 | clearInterval(torpedo.timerInterval); 87 | } 88 | }); 89 | 90 | // open the qTip 91 | $(torpedo.target).qtip({ 92 | id: "torpedo", 93 | content: { 94 | text: tooltipText(url), 95 | button: true, 96 | }, 97 | show: { 98 | event: e.type, 99 | ready: true, 100 | solo: true, 101 | delay: 20, 102 | }, 103 | hide: { 104 | fixed: true, 105 | event: "mouseleave", 106 | delay: 200, 107 | }, 108 | position: { 109 | my: "top left", 110 | at: "bottom left", 111 | target: $(torpedo.target), 112 | adjust: { 113 | y: 0, 114 | x: 0, 115 | mouse: false, 116 | method: "flip flip", 117 | resize: true, 118 | }, 119 | }, 120 | style: { 121 | tip: false, 122 | classes: "torpedoTooltip", 123 | }, 124 | events: { 125 | render: function (event, api) { 126 | torpedo.api = api; 127 | torpedo.tooltip = api.elements.content; 128 | 129 | preventClickEvent(torpedo.tooltip.find("#torpedoURL")[0], ["click"]); 130 | 131 | $(torpedo.tooltip).on("mouseenter", function () { 132 | torpedo.opened = true; 133 | }); 134 | 135 | $(torpedo.tooltip).on("mouseleave", function () { 136 | torpedo.opened = false; 137 | }); 138 | 139 | // init the tooltip elements and texts 140 | initTooltip(); 141 | updateTooltip(); 142 | }, 143 | hide: function () { 144 | if (torpedo.timerInterval != null) { 145 | clearInterval(torpedo.timerInterval); 146 | } 147 | }, 148 | }, 149 | }); 150 | } catch (err) { 151 | console.log(err); 152 | } 153 | }); 154 | } 155 | -------------------------------------------------------------------------------- /js/icon.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("click", (e) => { 2 | switch ($(e.target).attr("id")) { 3 | case "torpedoPage": 4 | chrome.tabs.create({ url: "https://secuso.aifb.kit.edu/TORPEDO.php" }); 5 | break; 6 | case "options": 7 | chrome.runtime.openOptionsPage(); 8 | break; 9 | case "error": 10 | if (e.target.classList == "error") { 11 | chrome.extension.getBackgroundPage().sendEmail(); 12 | } 13 | break; 14 | } 15 | }); 16 | 17 | function init() { 18 | console.log("loading-icon.js"); 19 | console.log($("#torpedoPage")); 20 | $("#torpedoPage").text(chrome.i18n.getMessage("extensionName")); 21 | $("#options").text(chrome.i18n.getMessage("options")); 22 | let loc = chrome.extension.getBackgroundPage().getStatus(); 23 | if (loc.works) { 24 | $("#error").attr("class", "working"); 25 | $("#error").text(chrome.i18n.getMessage("OK")); 26 | } else { 27 | $("#error").attr("class", "error"); 28 | $("#error").text(chrome.i18n.getMessage("error")); 29 | } 30 | } 31 | 32 | document.addEventListener("DOMContentLoaded", init); 33 | -------------------------------------------------------------------------------- /js/publicsuffixlist.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | publicsuffixlist.js - an efficient javascript implementation to deal with 3 | Mozilla Foundation's Public Suffix List 4 | Copyright (C) 2013 Raymond Hill 5 | License: pick the one which suits you: 6 | GPL v3 see 7 | APL v2 see 8 | */ 9 | 10 | /*! Home: https://github.com/gorhill/publicsuffixlist.js -- GPLv3 APLv2 */ 11 | 12 | /* 13 | This code is mostly dumb: I consider this to be lower-level code, thus 14 | in order to ensure efficiency, the caller is responsible for sanitizing 15 | the inputs. 16 | */ 17 | 18 | /******************************************************************************/ 19 | 20 | // A single instance of PublicSuffixList is enough. 21 | var torpedo = torpedo || {}; 22 | ;(function(root) { 23 | 24 | /******************************************************************************/ 25 | 26 | var exceptions = {}; 27 | var rules = {}; 28 | var selfieMagic = 'iscjsfsaolnm'; 29 | 30 | // This value dictate how the search will be performed: 31 | // < this.cutoffLength = indexOf() 32 | // >= this.cutoffLength = binary search 33 | var cutoffLength = 480; 34 | var mustPunycode = /[^a-z0-9.-]/; 35 | 36 | /******************************************************************************/ 37 | 38 | // In the context of this code, a domain is defined as: 39 | // "{label}.{public suffix}". 40 | // A single standalone label is a public suffix as per 41 | // http://publicsuffix.org/list/: 42 | // "If no rules match, the prevailing rule is '*' " 43 | // This means 'localhost' is not deemed a domain by this 44 | // code, since according to the definition above, it would be 45 | // evaluated as a public suffix. The caller is therefore responsible to 46 | // decide how to further interpret such public suffix. 47 | // 48 | // `hostname` must be a valid ascii-based hostname. 49 | 50 | function getDomain(hostname) { 51 | // A hostname starting with a dot is not a valid hostname. 52 | if ( !hostname || hostname.charAt(0) === '.' ) { 53 | return ''; 54 | } 55 | hostname = hostname.toLowerCase(); 56 | var suffix = getPublicSuffix(hostname); 57 | if ( suffix === hostname ) { 58 | return ''; 59 | } 60 | var pos = hostname.lastIndexOf('.', hostname.lastIndexOf('.', hostname.length - suffix.length) - 1); 61 | if ( pos <= 0 ) { 62 | return hostname; 63 | } 64 | return hostname.slice(pos + 1); 65 | } 66 | 67 | /******************************************************************************/ 68 | 69 | // Return longest public suffix. 70 | // 71 | // `hostname` must be a valid ascii-based string which respect hostname naming. 72 | 73 | function getPublicSuffix(hostname) { 74 | if ( !hostname ) { 75 | return ''; 76 | } 77 | // Since we slice down the hostname with each pass, the first match 78 | // is the longest, so no need to find all the matching rules. 79 | var pos; 80 | while ( true ) { 81 | pos = hostname.indexOf('.'); 82 | if ( pos < 0 ) { 83 | return hostname; 84 | } 85 | if ( search(exceptions, hostname) ) { 86 | return hostname.slice(pos + 1); 87 | } 88 | if ( search(rules, hostname) ) { 89 | return hostname; 90 | } 91 | if ( search(rules, '*' + hostname.slice(pos)) ) { 92 | return hostname; 93 | } 94 | hostname = hostname.slice(pos + 1); 95 | } 96 | // unreachable 97 | } 98 | 99 | /******************************************************************************/ 100 | 101 | // Look up a specific hostname. 102 | 103 | function search(store, hostname) { 104 | // Extract TLD 105 | var pos = hostname.lastIndexOf('.'); 106 | var tld, remainder; 107 | if ( pos < 0 ) { 108 | tld = hostname; 109 | remainder = hostname; 110 | } else { 111 | tld = hostname.slice(pos + 1); 112 | remainder = hostname.slice(0, pos); 113 | } 114 | var substore = store[tld]; 115 | if ( !substore ) { 116 | return false; 117 | } 118 | // If substore is a string, use indexOf() 119 | if ( typeof substore === 'string' ) { 120 | return substore.indexOf(' ' + remainder + ' ') >= 0; 121 | } 122 | // It is an array: use binary search. 123 | var l = remainder.length; 124 | var haystack = substore[l]; 125 | if ( !haystack ) { 126 | return false; 127 | } 128 | var left = 0; 129 | var right = Math.floor(haystack.length / l + 0.5); 130 | var i, needle; 131 | while ( left < right ) { 132 | i = left + right >> 1; 133 | needle = haystack.substr( l * i, l ); 134 | if ( remainder < needle ) { 135 | right = i; 136 | } else if ( remainder > needle ) { 137 | left = i + 1; 138 | } else { 139 | return true; 140 | } 141 | } 142 | return false; 143 | } 144 | 145 | /******************************************************************************/ 146 | 147 | // Parse and set a UTF-8 text-based suffix list. Format is same as found at: 148 | // http://publicsuffix.org/list/ 149 | // 150 | // `toAscii` is a converter from unicode to punycode. Required since the 151 | // Public Suffix List contains unicode characters. 152 | // Suggestion: use it's quite good. 153 | 154 | function parse(text, toAscii) { 155 | exceptions = {}; 156 | rules = {}; 157 | 158 | // http://publicsuffix.org/list/: 159 | // "... all rules must be canonicalized in the normal way 160 | // for hostnames - lower-case, Punycode ..." 161 | text = text.toLowerCase(); 162 | 163 | var lineBeg = 0, lineEnd; 164 | var textEnd = text.length; 165 | var line, store, pos, tld; 166 | 167 | while ( lineBeg < textEnd ) { 168 | lineEnd = text.indexOf('\n', lineBeg); 169 | if ( lineEnd < 0 ) { 170 | lineEnd = text.indexOf('\r', lineBeg); 171 | if ( lineEnd < 0 ) { 172 | lineEnd = textEnd; 173 | } 174 | } 175 | line = text.slice(lineBeg, lineEnd).trim(); 176 | lineBeg = lineEnd + 1; 177 | 178 | if ( line.length === 0 ) { 179 | continue; 180 | } 181 | 182 | // Ignore comments 183 | pos = line.indexOf('//'); 184 | if ( pos >= 0 ) { 185 | line = line.slice(0, pos); 186 | } 187 | 188 | // Ignore surrounding whitespaces 189 | line = line.trim(); 190 | if ( !line ) { 191 | continue; 192 | } 193 | 194 | if ( mustPunycode.test(line) ) { 195 | line = toAscii(line); 196 | } 197 | 198 | // Is this an exception rule? 199 | if ( line.charAt(0) === '!' ) { 200 | store = exceptions; 201 | line = line.slice(1); 202 | } else { 203 | store = rules; 204 | } 205 | 206 | // Extract TLD 207 | pos = line.lastIndexOf('.'); 208 | if ( pos < 0 ) { 209 | tld = line; 210 | } else { 211 | tld = line.slice(pos + 1); 212 | line = line.slice(0, pos); 213 | } 214 | 215 | // Store suffix using tld as key 216 | if ( !store.hasOwnProperty(tld) ) { 217 | store[tld] = []; 218 | } 219 | if ( line ) { 220 | store[tld].push(line); 221 | } 222 | } 223 | crystallize(exceptions); 224 | crystallize(rules); 225 | } 226 | 227 | /******************************************************************************/ 228 | 229 | // Cristallize the storage of suffixes using optimal internal representation 230 | // for future look up. 231 | 232 | function crystallize(store) { 233 | var suffixes, suffix, i, l; 234 | 235 | for ( var tld in store ) { 236 | if ( !store.hasOwnProperty(tld) ) { 237 | continue; 238 | } 239 | suffixes = store[tld].join(' '); 240 | // No suffix 241 | if ( !suffixes ) { 242 | store[tld] = ''; 243 | continue; 244 | } 245 | // Concatenated list of suffixes less than cutoff length: 246 | // Store as string, lookup using indexOf() 247 | if ( suffixes.length < cutoffLength ) { 248 | store[tld] = ' ' + suffixes + ' '; 249 | continue; 250 | } 251 | // Concatenated list of suffixes greater or equal to cutoff length 252 | // Store as array keyed on suffix length, lookup using binary search. 253 | // I borrowed the idea to key on string length here: 254 | // http://ejohn.org/blog/dictionary-lookups-in-javascript/#comment-392072 255 | 256 | i = store[tld].length; 257 | suffixes = []; 258 | while ( i-- ) { 259 | suffix = store[tld][i]; 260 | l = suffix.length; 261 | if ( !suffixes[l] ) { 262 | suffixes[l] = []; 263 | } 264 | suffixes[l].push(suffix); 265 | } 266 | l = suffixes.length; 267 | while ( l-- ) { 268 | if ( suffixes[l] ) { 269 | suffixes[l] = suffixes[l].sort().join(''); 270 | } 271 | } 272 | store[tld] = suffixes; 273 | } 274 | return store; 275 | } 276 | 277 | /******************************************************************************/ 278 | 279 | function toSelfie() { 280 | return { 281 | magic: selfieMagic, 282 | rules: rules, 283 | exceptions: exceptions 284 | }; 285 | } 286 | 287 | function fromSelfie(selfie) { 288 | if ( typeof selfie !== 'object' || typeof selfie.magic !== 'string' || selfie.magic !== selfieMagic ) { 289 | return false; 290 | } 291 | rules = selfie.rules; 292 | exceptions = selfie.exceptions; 293 | return true; 294 | } 295 | 296 | /******************************************************************************/ 297 | 298 | // Public API 299 | 300 | root = torpedo || window; 301 | 302 | root.publicSuffixList = { 303 | 'version': '1.0', 304 | 'parse': parse, 305 | 'getDomain': getDomain, 306 | 'getPublicSuffix': getPublicSuffix, 307 | 'toSelfie': toSelfie, 308 | 'fromSelfie': fromSelfie 309 | }; 310 | 311 | if ( typeof module !== "undefined" ) { 312 | module.exports = root.publicSuffixList; 313 | } else if ( typeof exports !== "undefined" ) { 314 | exports = root.publicSuffixList; 315 | } 316 | 317 | /******************************************************************************/ 318 | 319 | })(this); 320 | -------------------------------------------------------------------------------- /js/punycode.min.js: -------------------------------------------------------------------------------- 1 | /*! https://github.com/bestiejs/punycode.js v1.2.3 by @mathias */ 2 | (function(o){function e(o){throw RangeError(L[o])}function n(o,e){for(var n=o.length;n--;)o[n]=e(o[n]);return o}function t(o,e){return n(o.split(S),e).join(".")}function r(o){for(var e,n,t=[],r=0,u=o.length;u>r;)e=o.charCodeAt(r++),e>=55296&&56319>=e&&u>r?(n=o.charCodeAt(r++),56320==(64512&n)?t.push(((1023&e)<<10)+(1023&n)+65536):(t.push(e),r--)):t.push(e);return t}function u(o){return n(o,function(o){var e="";return o>65535&&(o-=65536,e+=R(55296|1023&o>>>10),o=56320|1023&o),e+=R(o)}).join("")}function i(o){return 10>o-48?o-22:26>o-65?o-65:26>o-97?o-97:x}function f(o,e){return o+22+75*(26>o)-((0!=e)<<5)}function c(o,e,n){var t=0;for(o=n?P(o/m):o>>1,o+=P(o/e);o>M*y>>1;t+=x)o=P(o/M);return P(t+(M+1)*o/(o+j))}function l(o){var n,t,r,f,l,d,s,a,p,h,v=[],g=o.length,w=0,j=I,m=A;for(t=o.lastIndexOf(F),0>t&&(t=0),r=0;t>r;++r)o.charCodeAt(r)>=128&&e("not-basic"),v.push(o.charCodeAt(r));for(f=t>0?t+1:0;g>f;){for(l=w,d=1,s=x;f>=g&&e("invalid-input"),a=i(o.charCodeAt(f++)),(a>=x||a>P((b-w)/d))&&e("overflow"),w+=a*d,p=m>=s?C:s>=m+y?y:s-m,!(p>a);s+=x)h=x-p,d>P(b/h)&&e("overflow"),d*=h;n=v.length+1,m=c(w-l,n,0==l),P(w/n)>b-j&&e("overflow"),j+=P(w/n),w%=n,v.splice(w++,0,j)}return u(v)}function d(o){var n,t,u,i,l,d,s,a,p,h,v,g,w,j,m,E=[];for(o=r(o),g=o.length,n=I,t=0,l=A,d=0;g>d;++d)v=o[d],128>v&&E.push(R(v));for(u=i=E.length,i&&E.push(F);g>u;){for(s=b,d=0;g>d;++d)v=o[d],v>=n&&s>v&&(s=v);for(w=u+1,s-n>P((b-t)/w)&&e("overflow"),t+=(s-n)*w,n=s,d=0;g>d;++d)if(v=o[d],n>v&&++t>b&&e("overflow"),v==n){for(a=t,p=x;h=l>=p?C:p>=l+y?y:p-l,!(h>a);p+=x)m=a-h,j=x-h,E.push(R(f(h+m%j,0))),a=P(m/j);E.push(R(f(a,0))),l=c(t,w,u==i),t=0,++u}++t,++n}return E.join("")}function s(o){return t(o,function(o){return E.test(o)?l(o.slice(4).toLowerCase()):o})}function a(o){return t(o,function(o){return O.test(o)?"xn--"+d(o):o})}var p="object"==typeof exports&&exports,h="object"==typeof module&&module&&module.exports==p&&module,v="object"==typeof global&&global;(v.global===v||v.window===v)&&(o=v);var g,w,b=2147483647,x=36,C=1,y=26,j=38,m=700,A=72,I=128,F="-",E=/^xn--/,O=/[^ -~]/,S=/\x2E|\u3002|\uFF0E|\uFF61/g,L={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},M=x-C,P=Math.floor,R=String.fromCharCode;if(g={version:"1.2.3",ucs2:{decode:r,encode:u},decode:l,encode:d,toASCII:a,toUnicode:s},"function"==typeof define&&"object"==typeof define.amd&&define.amd)define(function(){return g});else if(p&&!p.nodeType)if(h)h.exports=g;else for(w in g)g.hasOwnProperty(w)&&(p[w]=g[w]);else o.punycode=g})(this); 3 | -------------------------------------------------------------------------------- /js/redirect.js: -------------------------------------------------------------------------------- 1 | /** 2 | * resolve a redirection url, f.e. tinyurl 3 | */ 4 | function resolveRedirect(event) { 5 | showLoaderWithOverlay(); 6 | chrome.runtime.sendMessage({ name: "redirect", url: torpedo.url }, function (r) { 7 | torpedo.api.set("hide.event", "unfocus"); 8 | torpedo.api.set("hide.delay", 0); 9 | try { 10 | const href = new URL(r); 11 | setNewUrl(href); 12 | updateTooltip(); 13 | } catch (e) { console.log(e) } 14 | }); 15 | }; 16 | 17 | /** 18 | * resolve a referrer url, f.e. https://deref-gmx.net/mail/client/.. 19 | */ 20 | function resolveReferrer(r) { 21 | var url = torpedo.url; 22 | var arr1 = r.referrerPart1; 23 | var arr2 = r.referrerPart2; 24 | var arr3 = r.referrerPart3; 25 | 26 | for (var i = 0; i < (arr1.length + arr2.length); i++) { 27 | if (url.indexOf(arr1[i]) > -1) { 28 | var cut = arr3[i] ? arr3[i] : arr2[i]; 29 | var index = url.indexOf(cut); 30 | var temp = url.substring(index + cut.length, url.length); 31 | temp = decodeURIComponent(temp); 32 | try { 33 | const href = new URL(temp); 34 | setNewUrl(href); 35 | } catch (e) { } 36 | break; 37 | } 38 | } 39 | }; 40 | 41 | 42 | /** 43 | * checks if the current url is a referrer 44 | * @param url 45 | * @return resolved referrer or if the current url is no referrer or there was an error 46 | */ 47 | function matchReferrer(url) { 48 | const href = new URL(url); 49 | var hostnameURL = href.hostname; 50 | 51 | var referrerDomainArr = r.referrerPart1; 52 | var referrerPathArr = r.referrerPart2; 53 | var referrerAttributeArr = r.referrerPart3; 54 | 55 | if (referrerDomainArr === null || referrerPathArr === null || !hostnameURL) { 56 | return ""; 57 | } 58 | 59 | var indices = referrerDomainArr.map(function (element, i) { 60 | var domainParts = element.split("*").filter(String); 61 | return domainParts.every(function (el) { 62 | return hostnameURL.includes(el); 63 | }, hostnameURL) ? i : ''; 64 | }, hostnameURL).filter(String); 65 | 66 | for (var i = indices.length - 1; i >= 0; i--) { 67 | var ind = indices[i]; 68 | var pathParts = referrerPathArr[ind].split("[...]").filter(String); 69 | for (path of pathParts) { 70 | if (!url.includes(path)) { 71 | indices = indices.splice(i, 1); 72 | break; 73 | } 74 | } 75 | } 76 | 77 | for (index of indices) { 78 | var cut = referrerAttributeArr[index]; 79 | var urlAttrIndex = url.indexOf(cut); 80 | var temp = url.substring(urlAttrIndex + cut.length, url.length); 81 | temp = decodeURIComponent(temp); 82 | if (temp.startsWith("http") || temp.startsWith("https") || temp.startsWith("www")) { 83 | url = temp; 84 | return url; 85 | } 86 | 87 | } 88 | return ""; 89 | } 90 | 91 | 92 | -------------------------------------------------------------------------------- /js/status.js: -------------------------------------------------------------------------------- 1 | var torpedo = torpedo || {}; 2 | torpedo.state = "unknown"; 3 | r = null; 4 | 5 | /** 6 | * determine security status of domain by 7 | * looking up trusted, redirect, and user defined domains 8 | */ 9 | function getSecurityStatus(storage) { 10 | r = storage; 11 | 12 | var referrerURL = matchReferrer(torpedo.url); 13 | 14 | while (referrerURL != "") { 15 | try { 16 | const href = new URL(referrerURL); 17 | setNewUrl(href); 18 | } catch (e) {} 19 | 20 | referrerURL = matchReferrer(torpedo.url); 21 | torpedo.countRedirect++; 22 | } 23 | if (isRedirect(torpedo.domain)) { 24 | // short url 25 | torpedo.countShortURL++; 26 | if (!r.privacyModeActivated) { 27 | resolveRedirect(event); 28 | return "URLnachErmittelnButtonPrivacyMode"; 29 | } 30 | return "URLnachErmittelnButton2"; 31 | } else if (inTrusted(torpedo.domain)) { 32 | return "T1"; 33 | } else if (inUserList(torpedo.domain)) { 34 | return "T2"; 35 | } else if (torpedo.progUrl || torpedo.hasTooltip || isIP(torpedo.url)) { 36 | return "T32"; 37 | } else if (torpedo.countRedirect == 0) { 38 | if (isMismatch(torpedo.domain)) { 39 | return "T32"; 40 | } else { 41 | return "T31"; 42 | } 43 | } else { 44 | if (r.redirectModeActivated) { 45 | if (!isMismatch(torpedo.domain)) { 46 | return "T31"; 47 | } else { 48 | return "T32"; 49 | } 50 | } else { 51 | return "T32"; 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * checks if link contains a tooltip 58 | * @param eventTarget 59 | * @return url from tooltip or if there is no tooltip 60 | */ 61 | 62 | function hasTooltip(eventTarget) { 63 | if (eventTarget.hasAttribute("title")) { 64 | tooltipURL = eventTarget.getAttribute("title"); 65 | return tooltipURL; 66 | } 67 | return ""; 68 | } 69 | 70 | function isRedirect(url) { 71 | var lst = r.redirectDomains; 72 | for (var i = 0; i < lst.length; i++) { 73 | if (lst[i].indexOf(url) > -1) return true; 74 | } 75 | return false; 76 | } 77 | 78 | function isURLwithoutProtocol(string) { 79 | var isURLorDomainRegEx = /^(https?:\/\/)|^(www.)/; 80 | var matchesURLorDomain = string.match(isURLorDomainRegEx); 81 | 82 | if (matchesURLorDomain.length > 0) { 83 | if (matchesURLorDomain[0] == "www.") { 84 | return true; 85 | } 86 | } 87 | return false; 88 | } 89 | 90 | function isMismatch(domain) { 91 | try { 92 | var displayedLinkText = torpedo.target.innerText; 93 | if (isURLwithoutProtocol(displayedLinkText)) { 94 | displayedLinkText = "http://" + displayedLinkText; 95 | } 96 | 97 | const uri = new URL(displayedLinkText); 98 | var displayedLinkTextDom = extractDomain(uri.hostname); 99 | 100 | if ( 101 | displayedLinkTextDom != torpedo.oldDomain && 102 | displayedLinkTextDom != domain 103 | ) { 104 | return true; 105 | } 106 | } catch (e) { 107 | return false; 108 | } 109 | return false; 110 | } 111 | 112 | function isTooltipMismatch(tooltipURL, hrefURL) { 113 | if ( 114 | tooltipURL == "" || 115 | tooltipURL == undefined || 116 | hrefURL == "" || 117 | hrefURL == undefined 118 | ) { 119 | return false; 120 | } 121 | try { 122 | if (isURLwithoutProtocol(tooltipURL)) { 123 | tooltipURL = "http://" + tooltipURL; 124 | } 125 | var hrefDomain = extractDomain(hrefURL); 126 | var tooltipDomain = extractDomain(tooltipURL); 127 | return tooltipDomain != hrefDomain; 128 | } catch (e) { 129 | return false; 130 | } 131 | } 132 | 133 | function inTrusted(url) { 134 | if (r.trustedListActivated) { 135 | var lst = r.trustedDomains; 136 | for (var i = 0; i < lst.length; i++) { 137 | if (lst[i].indexOf(url) > -1) return true; 138 | } 139 | } 140 | return false; 141 | } 142 | 143 | function inUserList(url) { 144 | var lst = r.userDefinedDomains; 145 | for (var i = 0; i < lst.length; i++) { 146 | if (lst[i].indexOf(url) > -1) return true; 147 | } 148 | return false; 149 | } 150 | 151 | function isIP(address) { 152 | const ipWithProtocol = new RegExp( 153 | "^http[s]?://((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])" 154 | ); 155 | const ipWithoutProtocol = new RegExp( 156 | "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])" 157 | ); 158 | return ipWithProtocol.test(address) || ipWithoutProtocol.test(address); 159 | } 160 | 161 | function getSimilarTrustedList() { 162 | var similarTrustedList = r.similiarTrustedDomains; 163 | var userList = r.userDefinedDomains; 164 | 165 | for (var i = 0; i < userList.length; i++) { 166 | var domainUserList = userList[i]; 167 | var similarDomain = domainUserList.replace("-", ""); 168 | similarTrustedList.push(domainUserList); 169 | 170 | var regEx = /^[0-9]+$/; 171 | similarDomain = similarDomain.replace(regEx, ""); 172 | 173 | if (similarDomain.length >= 4) similarTrustedList.push(similarDomain); 174 | } 175 | 176 | return similarTrustedList; 177 | } 178 | 179 | /** 180 | * checks if the domain of the url is similar to a domain name in the green or blue list 181 | * @param url 182 | * @return {boolean} 183 | */ 184 | 185 | function isDomainExtension(domain) { 186 | var domainWithoutTLD = domain.split(".")[0]; 187 | var similarTrustedList = getSimilarTrustedList(); 188 | 189 | var okDomainList = r.trustedDomains; 190 | var userList = r.userDefinedDomains; 191 | 192 | okDomainList = okDomainList.concat(userList); 193 | okDomainList = okDomainList.concat(similarTrustedList); 194 | 195 | for (var j = 0; j < okDomainList.length; j++) { 196 | var okDomain = okDomainList[j]; 197 | var okDomainSplit = okDomainList[j].split("."); 198 | var okDomainWithoutTLD = okDomainSplit[0]; 199 | 200 | //check if a domain from the green, blue, or ok domain similar list was shortened and used in the link, e.g. immobilienscout.co.uk -> immobilienscout24.de 201 | if (okDomain.includes(domainWithoutTLD)) { 202 | var domainTLD = extractTLDfromDomain(domain); 203 | var domain2TLD = extractTLDfromDomain(okDomain); 204 | 205 | if (domainTLD != domain2TLD && domainTLD != "de" && domainTLD != "com") { 206 | return true; 207 | } 208 | } 209 | // does the link domain include a domain name from the green/blue list or from the ok domain similar list, e.g google-shop includes google 210 | if ( 211 | domain.includes(okDomainWithoutTLD) && 212 | okDomainWithoutTLD != "" && 213 | domainWithoutTLD != okDomainWithoutTLD 214 | ) { 215 | return true; 216 | } 217 | } 218 | return false; 219 | } 220 | -------------------------------------------------------------------------------- /js/timer.js: -------------------------------------------------------------------------------- 1 | torpedo.timerInterval = null; 2 | 3 | function preventClickEvent(eventTarget, eventTypes) { 4 | eventTypes.forEach(function (eventType) { 5 | $(eventTarget).unbind(eventType); 6 | }); 7 | 8 | eventTypes.forEach(function (eventType) { 9 | $(eventTarget).on(eventType, function (event) { 10 | event.preventDefault(); 11 | return false; 12 | }); 13 | }); 14 | } 15 | 16 | function reactivateLink(eventTarget, eventTypes) { 17 | eventTypes.forEach(function (eventType) { 18 | $(eventTarget).unbind(eventType); 19 | }); 20 | 21 | $(torpedo.target).bind("click", function (event) { 22 | processClick(); 23 | }); 24 | } 25 | 26 | function reactivateTooltipURL(tooltipURL) { 27 | try { 28 | tooltipURL.unbind("click"); 29 | tooltipURL.bind("click", function (event) { 30 | event.preventDefault(); 31 | chrome.storage.sync.get(null, function (r) { 32 | if (r.privacyModeActivated) { 33 | chrome.runtime.sendMessage({ 34 | name: "open", 35 | url: torpedo.oldUrl, 36 | }); 37 | } else { 38 | chrome.runtime.sendMessage({ name: "open", url: torpedo.url }); 39 | } 40 | }); 41 | processClick(); 42 | return false; 43 | }); 44 | } catch (e) { 45 | console.log(e); 46 | } 47 | } 48 | 49 | function isTimerActivated(storage, securityStatus) { 50 | switch (securityStatus) { 51 | case "T1": 52 | return storage.trustedTimerActivated; 53 | case "T2": 54 | return storage.userTimerActivated; 55 | default: 56 | return true; 57 | } 58 | } 59 | 60 | /** 61 | * countdown function for the temporal deactivation of URLs 62 | */ 63 | 64 | function countdown(time, state, clickLinkEventTypes) { 65 | if (torpedo.target.classList.contains("torpedoTimerFinished")) time = 0; 66 | 67 | var tooltip = torpedo.tooltip; 68 | 69 | $(tooltip.find("#torpedoTimer")[0]).show(); 70 | 71 | /** 72 | * assert time to tooltip text 73 | */ 74 | function showTime() { 75 | try { 76 | tooltip.find("#torpedoTimer")[0].textContent = chrome.i18n.getMessage("verbleibendeZeit", "" + time); 77 | } catch (e) {} 78 | } 79 | 80 | $(torpedo.target).addClass("torpedoTimerShowing"); 81 | 82 | const onWebsite = new URL(window.location.href); 83 | if (onWebsite.hostname === "owa.kit.edu") { 84 | $( 85 | "div._rp_U4.ms-font-weight-regular.ms-font-color-neutralDark.rpHighlightAllClass.rpHighlightBodyClass" 86 | ).unbind("click"); 87 | // document.removeEventListener('click', getEventListeners(document).click[0].listener) 88 | /* 89 | once script from owa can be used to remove eventlistener properly - insert here 90 | */ 91 | } 92 | 93 | showTime(); 94 | if (time > 0) time--; 95 | 96 | var timerInterval = setInterval(function timer() { 97 | showTime(); 98 | if (time == 0) { 99 | clearInterval(timerInterval); 100 | if (!isRedirect(torpedo.domain) && state != "T4" && state != "T4a") { 101 | $(torpedo.target).addClass("torpedoTimerFinished"); 102 | } 103 | 104 | reactivateLink(torpedo.target, clickLinkEventTypes); 105 | reactivateTooltipURL($(tooltip.find("#torpedoURL")[0])); 106 | } else { 107 | --time; 108 | } 109 | }, 1000); 110 | 111 | torpedo.timerInterval = timerInterval; 112 | } 113 | -------------------------------------------------------------------------------- /js/tutorial.js: -------------------------------------------------------------------------------- 1 | let activePageContent = 0; 2 | let lang = "en"; 3 | let overviewVisible = true; 4 | /* 5 | FOR EASY PLUG AND PLAY OF PAGES: 6 | * numbers start from 0 7 | * numbers are indicating the placement (order) 8 | * if you want an overview bubble you need to edit the tutorial html 9 | at the specified position to match the order (page 0 --> first overview) in the 10 | section "overview" 11 | * the page you insert needs to be implemented in the html in the section "tut-content" 12 | and will be flipped on and off as soon as it is called upon (through navigation) 13 | * If you want to add more than one page of a specific type 14 | than add "_case" and a specific term behind it (see below). 15 | This will allow to have different pictures within one general 16 | category of cases. F.e. simple-grey_case is one category with the 17 | sub-pages _no-phish and _phish. 18 | * Naming-convention for all before green_case is 19 | same name as css class; "-" in css, "_" in js 20 | */ 21 | const pages = { 22 | 0: "welcome", 23 | 1: "explanation", 24 | 2: "green_case", 25 | 3: "blue_case", 26 | 4: "simple-grey_case_phish", 27 | 5: "simple-grey_case_no-phish", 28 | 6: "warning-grey_case_phish", 29 | 7: "warning-grey_case_no-phish", 30 | 8: "configurations", 31 | }; 32 | const lastPage = Object.keys(pages).reduce((a, b) => 33 | parseInt(a) > parseInt(b) ? parseInt(a) : parseInt(b) 34 | ); 35 | let overviewCircles; 36 | 37 | // TESTING STUFF 38 | nrInCategory("warning-grey_case_no-phish", pages); 39 | 40 | // STARTING WHEN CONTENT IS LOADED ON PAGE 41 | $(document).ready(function () { 42 | // get language details 43 | lang = chrome.i18n.getUILanguage().substr(0, 2); 44 | 45 | overviewCircles = document.querySelectorAll(".overview-case"); 46 | 47 | // add eventlisteners 48 | // to overview for interactive clicking (since css and JS names differ there might be some adaptations) 49 | overviewCircles.forEach((circle) => { 50 | circle.addEventListener("click", (e) => { 51 | activePageContent = Object.entries(pages) 52 | .sort((a, b) => { 53 | a[0] - b[0]; 54 | }) 55 | .find((page) => { 56 | return circle.classList.contains(page[1].replace(/_/g, "-")) 57 | ? page 58 | : null; 59 | })[0]; 60 | show(); 61 | }); 62 | }); 63 | // to nav-buttons 64 | $("#prev").on("click", function (e) { 65 | if (activePageContent > 0) show(--activePageContent); 66 | }); 67 | $("#next").on("click", function (e) { 68 | if (activePageContent < lastPage) show(++activePageContent); 69 | }); 70 | $("#finish").on("click", function (e) { 71 | e.target.classList.contains("disabled") 72 | ? false 73 | : chrome.runtime.sendMessage({ name: "close" }); 74 | }); 75 | 76 | init(); 77 | show(activePageContent); 78 | }); 79 | 80 | function show() { 81 | //console.log(`We are currently on page: ${activePageContent}`); 82 | activateCurrentPageElements(); 83 | showPageContent(); 84 | } 85 | 86 | function activateCurrentPageElements() { 87 | // possibility to adapt the visibility of overview-bubbles 88 | if (overviewVisible) { 89 | document.querySelector(".overview").style.display = "flex"; 90 | // remove selected from all and then assign selected to the active circle 91 | overviewCircles.forEach((circle) => { 92 | circle.classList.remove("selected"); 93 | circle.classList.contains(pages[activePageContent].replace(/_/g, "-")) 94 | ? circle.classList.add("selected") 95 | : null; 96 | }); 97 | } else { 98 | document.querySelector(".overview").style.display = "none"; 99 | } 100 | 101 | // logic for buttons (which are active/deactivated) 102 | activePageContent == Object.keys(pages).length - 1 103 | ? document.querySelector("#finish").classList.remove("disabled") 104 | : document.querySelector("#finish").classList.add("disabled"); 105 | } 106 | 107 | function showPageContent() { 108 | // not displaying anything 109 | $(".tut-content > div").addClass("off"); 110 | 111 | pages[activePageContent].includes("_case") 112 | ? // if it's an example 113 | prepExample() 114 | : // if it's a different page 115 | prepNoExamplePage(); 116 | } 117 | /** 118 | * Initialize the entire tutorial with correct lang 119 | */ 120 | function init() { 121 | // see if we want overview or not 122 | activateCurrentPageElements(); 123 | // at beginning for language´ 124 | 125 | // page 'welcome' 126 | $("#welcome-title").html(getMsg("welcome_title")); 127 | $("#introduction-txt").html(getMsg("introduction_txt")); 128 | $("#technical-bg-title").html(getMsg("technical_background_title")); 129 | $("#technical-bg-txt").html(getMsg("technical_background_txt")); 130 | $("#functionality-title").html(getMsg("functionality_title")); 131 | $("#functionality-txt").html(getMsg("functionality_txt")); 132 | $(".welcome").removeClass("off"); 133 | 134 | // page 'explanation' 135 | $("#functionality-explanation-title").text( 136 | getMsg("functionality_explanation_title") 137 | ); 138 | for (let i = 1; i < 8; i++) { 139 | $(`#functionality-explanation-txt-${i}`).html( 140 | getMsg(`functionality_explanation_txt_${i}`) 141 | ); 142 | } 143 | $(`#domain-explain`).text(getMsg(`domain_translation`)); 144 | // pages of the cases and their explanations 145 | $("#green-case-showcase-title").text(getMsg("green_case_title")); 146 | $("#blue-case-showcase-title").text(getMsg("blue_case_title")); 147 | $("#simple-grey-case-showcase-title").text(getMsg("simple_grey_case_title")); 148 | $("#warning-grey-case-showcase-title").text( 149 | getMsg("warning_grey_case_title") 150 | ); 151 | $("#red-case-showcase-title").text(getMsg("red_case_title")); 152 | $("#green-case-showcase-img").attr( 153 | "src", 154 | `/img/examples/${lang}/green_case_${lang}.svg` 155 | ); 156 | $("#blue-case-showcase-img").attr( 157 | "src", 158 | `/img/examples/${lang}/blue_case_${lang}.svg` 159 | ); 160 | $("#simple-grey-case-showcase-img").attr( 161 | "src", 162 | `/img/examples/${lang}/simple-grey_case_no-phish_${lang}.svg` 163 | ); 164 | $("#warning-grey-case-showcase-img").attr( 165 | "src", 166 | `/img/examples/${lang}/warning-grey_case_no-phish_${lang}.svg` 167 | ); 168 | $("#red-case-showcase-img").attr( 169 | "src", 170 | `/img/examples/${lang}/red_case_${lang}.svg` 171 | ); 172 | // making examples clickable by binding them to pages depending on first word of css selector 173 | let showcases = Array.from(document.querySelectorAll(".show-case-card.card")); 174 | showcases.forEach((showcase) => { 175 | showcase.addEventListener("click", (e) => { 176 | let keyword = showcase.classList[0].split("-")[0]; 177 | activePageContent = findFirstByIndex(pages, keyword); 178 | show(); 179 | }); 180 | }); 181 | 182 | // page configurations 183 | $("#contextmenu-img").attr( 184 | "src", 185 | `/img/examples/${lang}/simple-grey_case_contextmenu_${lang}.svg` 186 | ); 187 | $("#special-cases-title").text(getMsg("special_cases_title")); 188 | $("#special-cases-txt").text(getMsg("special_cases_txt")); 189 | 190 | $("#settings-title").text(getMsg("settings_title")); 191 | $("#settings-subtitle").text(getMsg("settings_subtitle")); 192 | $("#settings-img").attr("src", `/img/examples/${lang}/settings_${lang}.png`); 193 | Array.from(document.querySelectorAll(".settings-option")).forEach( 194 | (option, index) => { 195 | $(`#settings-option-${index + 1}`).html( 196 | getMsg(`settings_option_${index}`) 197 | ); 198 | } 199 | ); 200 | } 201 | 202 | // HELPER FUNCTIONS 203 | 204 | // ANALYZING PAGES 205 | /** 206 | * 207 | * @param {*} object object containing all pages 208 | * 209 | * reads out all the names of pages and concatenating those to selector to 210 | * easily display none all pages and activate the appropriate one. 211 | */ 212 | function readOutCSSClassesConcatenatedNotExamples(object) { 213 | let results = Object.values(object).filter((entry) => { 214 | return !entry.match(/_case/g) ? entry : null; 215 | }); 216 | return results; 217 | } 218 | /** 219 | * 220 | * @param {*} obj object to go through 221 | * @param {*} firstExampleValue RegEx to look for, if none is specified first value containing the RegEx "_case" is chosen 222 | * 223 | * @returns first match containing firstExampleValue, if none matches returns null 224 | */ 225 | function findFirstByIndex(obj, firstExampleValue = null) { 226 | let result = firstExampleValue 227 | ? Object.entries(obj) 228 | .sort((a, b) => a[0] - b[0]) 229 | .filter((entry) => entry[1].match(firstExampleValue)) 230 | : Object.entries(obj) 231 | .sort((a, b) => a[0] - b[0]) 232 | .filter((entry) => entry[1].match(/_case/g)); 233 | return result.length ? result[0][0] : null; 234 | } 235 | /** 236 | * 237 | * @param {*} obj object to go through 238 | * @param {*} firstExampleValue RegEx to look for, if none is specified first value containing the RegEx "_case" is used 239 | * 240 | * @returns first match containing lastExampleValue, if none matches returns null 241 | */ 242 | function findLastByIndex(obj, lastExampleValue = null) { 243 | let result = lastExampleValue 244 | ? Object.entries(obj) 245 | .sort((b, a) => a[0] - b[0]) 246 | .filter((entry) => entry[1].match(lastExampleValue)) 247 | : Object.entries(obj) 248 | .sort((b, a) => a[0] - b[0]) 249 | .filter((entry) => entry[1].match(/_case/g)); 250 | return result.length ? result[0][0] : null; 251 | } 252 | /** 253 | * 254 | * @param {*} string word that shall be cut off at stopper 255 | * @param {*} stopper last part in word 256 | */ 257 | function wordStopper(string, stopper) { 258 | return string.includes(stopper) 259 | ? string.substring(0, string.indexOf(stopper)).concat(stopper) 260 | : string; 261 | } 262 | /** 263 | * 264 | * @param {*} string word where the last part shall be "_case" 265 | * 266 | * special case of wordStopper, stopper is "_case" 267 | */ 268 | function caseStopper(string) { 269 | return wordStopper(string, "_case"); 270 | } 271 | 272 | /** 273 | * 274 | * @param {*} object object/array from which to id the key/index 275 | * @param {*} value value of the object of which the key ought to be found 276 | * @param {*} first determines whether to output first or last instance of matches. Defaults to first. 277 | */ 278 | function keyByValue(object, value, first = true) { 279 | if (first) return Object.keys(object).find((key) => object[key] === value); 280 | else { 281 | let result = Object.keys(object) 282 | .filter((key) => object[key] === value) 283 | .sort((b, a) => a[0] - b[0])[0]; 284 | return result; 285 | } 286 | } 287 | /** 288 | * 289 | * @param {*} category category that is searched for (naming convention, _case as indicator of a category) 290 | * @param {*} obj obj to go through 291 | */ 292 | function findAmountOfExamplesOfCategory(category, obj) { 293 | let amount = 0; 294 | amount = Object.values(obj).filter((page) => { 295 | return page.includes(caseStopper(category)); 296 | }).length; 297 | return amount; 298 | } 299 | /** 300 | * 301 | * @param {*} category page to be analyzed 302 | * @param {*} obj object to go through 303 | * 304 | * Because objects do not grant order, the index has to be analyzed to tell which nr it takes 305 | */ 306 | function nrInCategory(category, obj) { 307 | let sortedCats = Object.entries(obj).filter((page) => { 308 | return page[1].includes(caseStopper(category)); 309 | }); 310 | let nrOfCat = 0; 311 | for (el of sortedCats) keyByValue(pages, category) > el[0] ? nrOfCat++ : null; 312 | return nrOfCat; 313 | } 314 | 315 | // PAGE PREPARATION 316 | /** 317 | * 318 | * @param {*} msg msg to be caught in ling 319 | * 320 | * This function is shorter but works like chrome.i18n.getMessage(msg); 321 | */ 322 | function getMsg(msg) { 323 | return chrome.i18n.getMessage(msg.replace(/-/g, "_")); 324 | } 325 | 326 | function prepExample() { 327 | // showing image 328 | $(".svg-in-img").attr( 329 | "src", 330 | `./img/examples/${lang}/${pages[activePageContent]}_${lang}.svg` 331 | ); 332 | 333 | // filling card 334 | // starting with content each example has 335 | $("#example-title").html( 336 | getMsg(`${caseStopper(pages[activePageContent])}_title`) 337 | ); 338 | $("#category-explanation").html( 339 | getMsg(`${caseStopper(pages[activePageContent])}_category`) 340 | ); 341 | $("#explanation-of-specific-link").html( 342 | getMsg(`${pages[activePageContent]}_specific_link_explanation`) 343 | ); 344 | // THIS SECTION IS ONLY NECESSARY IF A CATEGORY HAS ADDITIONAL INFO OR MORE THAN ONE CASE 345 | let amountActiveCat = findAmountOfExamplesOfCategory( 346 | pages[activePageContent], 347 | pages 348 | ); 349 | let context = getMsg(`${pages[activePageContent]}_context`); 350 | context 351 | ? ($("#example-context").html( 352 | `${getMsg("example")}${ 353 | amountActiveCat > 1 354 | ? ` ${nrInCategory(pages[activePageContent], pages) + 1}` 355 | : "" 356 | }: ` + context 357 | ), 358 | $("#additional-info").removeClass("off")) 359 | : $("#additional-info").addClass("off"); 360 | 361 | if (amountActiveCat > 1) { 362 | $("#more-than-one-example").html( 363 | getMsg(`${caseStopper(pages[activePageContent])}_more_than_one`) 364 | ); 365 | $("#more-than-one").removeClass("off"); 366 | } else { 367 | $("#more-than-one").addClass("off"); 368 | } 369 | // making it visible again 370 | $(".example-wrapper").removeClass("off"); 371 | } 372 | 373 | function prepNoExamplePage() { 374 | $(`.${pages[activePageContent].replace(/_/g, "-")}`).removeClass("off"); 375 | } 376 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "author": "SECUSO", 4 | "applications": { 5 | "gecko": { 6 | "id": "torpedo@tu-darmstadt.de" 7 | } 8 | }, 9 | "name": "__MSG_extensionName__", 10 | "version": "3.2.2", 11 | "default_locale": "de", 12 | "description": "__MSG_extensionDescription__", 13 | "background": { 14 | "scripts": [ 15 | "js/jquery-3.4.1.min.js", 16 | "js/punycode.min.js", 17 | "background.js" 18 | ] 19 | }, 20 | "permissions": [ 21 | "", 22 | "tabs", 23 | "storage", 24 | "messagesModify" 25 | ], 26 | "options_ui": { 27 | "page": "options.html", 28 | "open_in_tab": true 29 | }, 30 | "icons": { 31 | "38": "img/icon38.png", 32 | "64": "img/icon64.png" 33 | }, 34 | "web_accessible_resources": [ 35 | "img/*.png", 36 | "img/*.svg" 37 | ] 38 | } -------------------------------------------------------------------------------- /options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

16 |
17 | 23 | 24 |
25 |
26 |
27 | 28 |

29 |
30 |
31 |

32 | 33 |

34 |
35 |
36 |
37 | 38 |

39 |
40 |
41 |
42 |
43 | 44 |

45 |
46 |
47 |
48 |
49 | 50 |

51 |
52 |
53 |
54 |
55 | 56 |

57 |
58 |
59 |
60 |
61 | 62 |

63 |
64 |
65 |
66 | 67 |
68 |

69 |
70 | 71 |

72 |
73 |
74 | 75 |
76 |

77 | 78 |
79 | 80 | 81 |

82 |
83 |
84 | 85 |
86 |

87 |

88 | 89 | 90 | 91 | 92 | 93 |
94 | 95 |

96 |

97 |

98 | 99 |

100 | 101 |

102 | 103 | 104 |

105 |
106 | 107 |
108 |

109 |

110 | 111 | 112 | 113 | 114 | 115 |
116 |
117 | 118 | 119 |

120 |
121 |
122 |
123 | 124 |
125 | 126 | 127 | 128 |
129 | 130 |

131 |
132 | 133 | 134 | 135 | 136 |
137 | 138 | 139 | 140 | 141 | 142 |
143 |
144 | 145 | 146 | -------------------------------------------------------------------------------- /tutorial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | TORPEDO Tutorial 14 | 20 | 21 | 22 | 23 | 24 |
25 |
26 |

27 | TORPEDO 32 |

33 |
34 | 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |

54 |

55 |

56 |
    57 |
  • 58 |
  • 59 |
60 |

61 |

62 |

63 |

64 |
65 |
66 |

67 |

68 |

69 |

70 |

71 |

72 |

73 |

74 |

75 |
76 |
77 |
78 |

79 |

80 |

81 | 82 |

83 |

84 | 85 |

86 | google.de 87 |

88 |

89 | 90 |

91 |
92 |
93 |
94 |

95 | cases showing 96 |
97 |
98 |

99 | cases showing 100 |
101 |
102 |

103 | cases showing 104 |
105 |
106 |

107 | cases showing 108 |
109 |
110 |
111 |
112 |
113 |

114 |

115 |
116 |
117 |

Phishinglegitimes

118 |
119 |
120 |

121 |
122 | 123 |
124 |
125 | green_example 126 |
127 |
128 |
129 |
130 |
131 |
132 | picture showing that you can get to settings via contextmenue 133 |
134 |
135 |

136 |

137 |
138 |
139 |
140 |
141 |
142 |
143 |

144 |

145 |
    146 |
  1. 147 |
  2. 148 |
  3. 149 |
  4. 150 |
151 |
152 |
153 | showing different options for TORPEDO 154 |
155 |
156 |
157 |
158 |
159 |
160 | 177 | 178 | 179 | --------------------------------------------------------------------------------