aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgrant-kun <[email protected]>2022-10-13 13:18:42 -0500
committergrant-kun <[email protected]>2022-10-13 13:18:42 -0500
commit26d50b8e63f79e48652840a54567b059d1f73766 (patch)
tree08d81de8bf558e80d0fde43e6c400650ae4786e8
parentafdd65e44c3a1a89d1aaa1c089508bd86477d727 (diff)
adding stuff
-rw-r--r--html/mail.html38
-rw-r--r--index.ts67
-rw-r--r--package.json3
-rw-r--r--readme.md4
-rw-r--r--src/autolink.js245
-rw-r--r--src/quoted-printable.js153
6 files changed, 486 insertions, 24 deletions
diff --git a/html/mail.html b/html/mail.html
index f726505..6c66f3a 100644
--- a/html/mail.html
+++ b/html/mail.html
@@ -4,19 +4,23 @@
<title>mail</title>
<script src="/src/bundle.js"></script>
<script src=" https://unpkg.com/showdown/dist/showdown.min.js"></script>
+ <script src='/src/autolink.js'></script>
+ <script src='/src/quoted-printable.js'></script>
<style>
.split {
height: 90%;
- width: 50%;
+ width: 51%;
position: fixed;
z-index: 1;
top: 0;
overflow-x: hidden;
- padding-top: 10px;
- }
+ }
+ body {
+ background-color: #444444;
+ }
svg.tea {
@@ -278,14 +282,21 @@
}
};
let emails = []
+ let bod
+ let html = false
function update() {
//console.log('hi')
let promie = new Promise((resolve, reject) => {
sendenc('/get/update', { 'user': 'root', 'requested': 0, 'login_key': getCookie('login_key') }).then(res => {
res = JSON.parse(res)
console.log('parsed')
- emails = res.reverse()
+ emails = res.messages.reverse()
+ //console.log(res)
console.log(res)
+ bod = res.bod
+ if (res.bod == 'body[2]') {
+ html = true
+ }
umail()
resolve(res)
})
@@ -309,13 +320,18 @@
let mypriv, mypub, pub, kekw
let preview = -1
var converter = new showdown.Converter()
+
async function lm(index) {
- let m = ((emails[index]['body[1]']))
- var linkify = m.replace(/(<a href=")?((https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)))(">(.*)<\/a>)?/gi, function () {
- return '<a href="' + arguments[2] + '">' + (arguments[7] || arguments[2]) + '</a>'
- });
+ let m
+ if (html) {
+ m = autoLink((emails[index]['body[2]']))
+ } else {
+ m = converter.makeHtml(autoLink((quotedPrintable.decode(emails[index]['body[0]']))))
+ }
+
+
document.getElementById('box').style.display = 'block'
- document.getElementById('view').innerHTML = converter.makeHtml(linkify)
+ document.getElementById('view').innerHTML = (m)
}
@@ -329,7 +345,7 @@
c = '#395B64'
}
evo = !evo
- ret += '<div onclick="lm(' + emails.indexOf(email) + ')" style="white-space: pre-wrap;color:#A5C9CA;border-radius:10px;max-width:40%;min-width:400px;padding:20px;background-color:' + c + ';">'
+ ret += '<div onclick="lm(' + emails.indexOf(email) + ')" style="height:10%;white-space: pre-wrap;color:#A5C9CA;border-radius:5px;max-width:40%;min-width:400px;padding:20px;background-color:' + c + ';">'
ret += '<tt><b><font size="4">sub:' + email.envelope.subject + '</font></b></br>frm:' + email.envelope.from[0].address + '</br><sub style="color:#E7F6F2;">' + email.envelope.date + '</sub></tt></br></div><div style="height:2px;"></div>'
}
@@ -345,7 +361,7 @@
if (getCookie('login_key') == null) {
window.location.href = '/'
}
- await init()
+ await update()
//return
//document.getElementsByClassName('loading')[0].style.display = 'none'
let xx = document.getElementsByClassName('card')[0]
diff --git a/index.ts b/index.ts
index 4fb34fc..78de797 100644
--- a/index.ts
+++ b/index.ts
@@ -1,4 +1,5 @@
import { readFileSync, writeFileSync } from "fs"
+import { LogLevel } from "node-ts";
var privateKey = readFileSync('certs/selfsigned.key', 'utf8');
var certificate = readFileSync('certs/selfsigned.crt', 'utf8');
var http = require('http');
@@ -13,7 +14,33 @@ app.use(bodyParser.json());
const NodeRSA = require('node-rsa');
var ip = require("ip")
var crypt = require('crypto');
-
+Object.defineProperty(global, '__stack', {
+ get: function() {
+ var orig = Error.prepareStackTrace;
+ Error.prepareStackTrace = function(_, stack) {
+ return stack;
+ };
+ var err = new Error;
+ Error.captureStackTrace(err, arguments.callee);
+ var stack = err.stack;
+ Error.prepareStackTrace = orig;
+ return stack;
+ }
+ });
+
+ Object.defineProperty(global, '__line', {
+ get: function() {
+ // @ts-ignore
+ return __stack[1].getLineNumber();
+ }
+ });
+
+ Object.defineProperty(global, '__function', {
+ get: function() {
+ // @ts-ignore
+ return __stack[1].getFunctionName();
+ }
+ });
const IV = "5183666c72eec9e4"; //!not really sure what this is lol
//TODO: learn what IV is
var encrypt = ((val:any,ENC_KEY:any) => {
@@ -34,7 +61,11 @@ var decrypt = ((encrypted:any,ENC_KEY:any) => {
//
function log(m:any){
var date = new Date;
- console.log('['+date.getHours()+':'+date.getMinutes()+':'+date.getSeconds()+'] ' + m.toString())
+ let e:any = new Error();
+ let frame = e.stack.split("\n")[2]; // change to 3 for grandparent func
+ let lineNumber = frame.split(":").reverse()[1];
+ let functionName = frame.split(" ")[5];
+ console.log('['+functionName+'/'+lineNumber+'][./index.ts]'+'['+date.getHours()+':'+date.getMinutes()+':'+date.getSeconds()+'] ' + m.toString())
}
function d(){
var date = new Date;
@@ -72,14 +103,23 @@ app.post('/mail/get/update',(req:any,res:any)=>{
var client = new ImapClient(mail.host, parseInt(mail.port), {
auth: {
user: mail.address,
- pass: mail.creds
- }
+ pass: mail.creds,
+
+ },logLevel:1000
});
client.connect().then(()=>{
//['uid', 'flags','envelope'] for just header stuff
//['uid', 'flags','envelope','body']
- //body 0 is plani, 1 is html
- client.listMessages('INBOX', '1:*', ['uid', 'flags','envelope','bodystructure','body[1]' ]).then((messages:any) => {
+ //body 0 is plani, 1 is plain
+ let bo="body[0]"
+ for(let user of users){
+ if(user.name==dec.data.user){
+ if(user.settings.html){
+ bo="body[2]"
+ }
+ }
+ }
+ client.listMessages('INBOX', '1:*', ['uid', 'flags','envelope','bodystructure',bo ]).then((messages:any) => {
const skey = new NodeRSA()
skey.importKey(keyring[req.body.sid].theirpub,'pkcs8-public')
for(let user of users){
@@ -93,8 +133,7 @@ app.post('/mail/get/update',(req:any,res:any)=>{
}
}
//console.log(users,(JSON.stringify(messages)))
-
- res.send(JSON.stringify({data:skey.encrypt(JSON.stringify(messages),'base64'),enc:true,html:true}))
+ res.send(JSON.stringify({data:skey.encrypt(JSON.stringify({messages:messages,bod:bo}),'base64'),enc:true,html:true}))
client.close()
});
})
@@ -164,6 +203,12 @@ app.get('/kanna.txt', (req:any, res:any) => {
app.get('/src/bundle.js', (req:any, res:any) => {
res.sendFile(__dirname+'/src/bundle.js')
})
+app.get('/src/autolink.js', (req:any, res:any) => {
+ res.sendFile(__dirname+'/src/autolink.js')
+})
+app.get('/src/quoted-printable.js', (req:any, res:any) => {
+ res.sendFile(__dirname+'/src/quoted-printable.js')
+})
app.get('/src/lights-out.gif', (req:any, res:any) => {
res.sendFile(__dirname+'/src/lights-out.gif')
})
@@ -214,13 +259,13 @@ app.use((req:any, res:any, next:any) => {
var httpServer = http.createServer(app);
var credentials = {key: privateKey, cert: certificate};
var httpsServer = https.createServer(credentials, app);
-app.listen(8008,()=>{
+app.listen(8008,function local(){
log(`kanna is local http://${ip.address()}:8080`)
})
-httpServer.listen(80, () => {
+httpServer.listen(80, function http() {
log(`kanna is on http://${ip.address()} click on me click on me! :3`)
})
-httpsServer.listen(443, () => {
+httpsServer.listen(443, function https() {
log(`kanna is secure now too!! https://${ip.address()}`)
})
//end
diff --git a/package.json b/package.json
index 32dba1c..1afa863 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,8 @@
"ip": "^1.1.8",
"md5": "^2.3.0",
"node-rsa": "^1.1.1",
- "openpgp": "^5.5.0"
+ "openpgp": "^5.5.0",
+ "utf8": "^3.0.0"
},
"devDependencies": {
"emailjs-imap-client": "^3.1.0"
diff --git a/readme.md b/readme.md
index ed88be7..8a988ce 100644
--- a/readme.md
+++ b/readme.md
@@ -70,10 +70,12 @@ visit the [main git](https://git.disroot.org/grantsquires/kanna-site) or the [gi
- [ ] draft
- [ ] forward
- [ ] sender info
- - [ ] allow for email account adding (soon)
+ - [ ] allow for email account adding
- [ ] docs
- [ ] extra pages
- [x] 404 page
- [ ] sub domains
+ - [ ] make my own libs
+ - [ ] encryption (md5 hashing, and rsa)
FeMail (iron mail)
diff --git a/src/autolink.js b/src/autolink.js
new file mode 100644
index 0000000..c04a0d2
--- /dev/null
+++ b/src/autolink.js
@@ -0,0 +1,245 @@
+const re = {
+ http: /.*?:\/\//g,
+ url: /(\s|^)((https?|ftp):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\w-\/\?\=\#\.])*/gi,
+ image: /\.(jpe?g|png|gif)$/,
+ email:
+ /(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/gi,
+ cloudmusic: /http:\/\/music\.163\.com\/#\/song\?id=(\d+)/i,
+ kickstarter:
+ /(https?:\/\/www\.kickstarter\.com\/projects\/\d+\/[a-zA-Z0-9_-]+)(\?\w+\=\w+)?/i,
+ youtube:
+ /https?:\/\/www\.youtube\.com\/watch\?v=([a-zA-Z0-9_-]+)(\?\w+\=\w+)?/i,
+ vimeo:
+ /https?:\/\/(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/[^\/]*\/videos\/|album\/\d+\/video\/|video\/|)(\d+)(?:$|\/|\?)/i,
+ youku:
+ /https?:\/\/v\.youku\.com\/v_show\/id_([a-zA-Z0-9_\=-]+).html(\?\w+\=\w+)?(\#\w+)?/i,
+};
+/**
+ * AutoLink constructor function
+ *
+ * @param {String} text
+ * @param {Object} options
+ * @constructor
+ */
+function AutoLink(string, options = {}) {
+ this.string = options.safe ? safe_tags_replace(string) : string;
+ this.options = options;
+ this.attrs = "";
+ this.linkAttr = "";
+ this.imageAttr = "";
+ if (this.options.sharedAttr) {
+ this.attrs = getAttr(this.options.sharedAttr);
+ }
+ if (this.options.linkAttr) {
+ this.linkAttr = getAttr(this.options.linkAttr);
+ }
+ if (this.options.imageAttr) {
+ this.imageAttr = getAttr(this.options.imageAttr);
+ }
+}
+
+AutoLink.prototype = {
+ constructor: AutoLink,
+ /**
+ * call relative functions to parse url/email/image
+ *
+ * @returns {String}
+ */
+ parse: function () {
+ var shouldReplaceImage = defaultTrue(this.options.image);
+ var shouldRelaceEmail = defaultTrue(this.options.email);
+ var shouldRelaceBr = defaultTrue(this.options.br);
+
+ var result = "";
+ if (!shouldReplaceImage) {
+ result = this.string.replace(re.url, this.formatURLMatch.bind(this));
+ } else {
+ result = this.string.replace(re.url, this.formatIMGMatch.bind(this));
+ }
+ if (shouldRelaceEmail) {
+ result = this.formatEmailMatch.call(this, result);
+ }
+ if (shouldRelaceBr) {
+ result = result.replace(/\r?\n/g, "<br />");
+ }
+ return result;
+ },
+ /**
+ * @param {String} match
+ * @returns {String} Offset 1
+ */
+ formatURLMatch: function (match, p1) {
+ match = prepHTTP(match.trim());
+ if (this.options.cloudmusic || this.options.embed) {
+ if (match.indexOf("music.163.com/#/song?id=") > -1) {
+ return match.replace(
+ re.cloudmusic,
+ p1 +
+ '<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=330 height=86 src="http://music.163.com/outchain/player?type=2&id=$1&auto=1&height=66"></iframe>'
+ );
+ }
+ }
+ if (this.options.kickstarter || this.options.embed) {
+ if (re.kickstarter.test(match)) {
+ return match.replace(
+ re.kickstarter,
+ p1 +
+ '<iframe width="480" height="360" src="$1/widget/video.html" frameborder="0" scrolling="no"> </iframe>'
+ );
+ }
+ }
+ if (this.options.vimeo || this.options.embed) {
+ if (re.vimeo.test(match)) {
+ return match.replace(
+ re.vimeo,
+ p1 +
+ '<iframe width="500" height="281" src="https://player.vimeo.com/video/$1" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>'
+ );
+ }
+ }
+ if (this.options.youtube || this.options.embed) {
+ if (re.youtube.test(match)) {
+ return match.replace(
+ re.youtube,
+ p1 +
+ '<iframe width="560" height="315" src="https://www.youtube.com/embed/$1" frameborder="0" allowfullscreen></iframe>'
+ );
+ }
+ }
+ if (this.options.youku || this.options.embed) {
+ if (re.youku.test(match)) {
+ return match.replace(
+ re.youku,
+ p1 +
+ '<iframe height=498 width=510 src="http://player.youku.com/embed/$1" frameborder=0 allowfullscreen></iframe>'
+ );
+ }
+ }
+ var text = this.options.removeHTTP ? removeHTTP(match) : match;
+ return (
+ p1 +
+ '<a href="' +
+ match +
+ '"' +
+ this.attrs +
+ this.linkAttr +
+ ">" +
+ text +
+ "</a>"
+ );
+ },
+ /**
+ * @param {String} match
+ * @param {String} Offset 1
+ */
+ formatIMGMatch: function (match, p1) {
+ match = match.trim();
+ var isIMG = re.image.test(match);
+ if (isIMG) {
+ return (
+ p1 +
+ '<img src="' +
+ prepHTTP(match.trim()) +
+ '"' +
+ this.attrs +
+ this.imageAttr +
+ "/>"
+ );
+ }
+ return this.formatURLMatch(match, p1);
+ },
+ /**
+ * @param {String} text
+ */
+ formatEmailMatch: function (text) {
+ return text.replace(
+ re.email,
+ '<a href="mailto:$&"' + this.attrs + this.linkAttr + ">$&</a>"
+ );
+ },
+};
+
+/**
+ * return true if undefined
+ * else return itself
+ *
+ * @param {Boolean} val
+ * @returns {Boolean}
+ */
+function defaultTrue(val) {
+ return typeof val === "undefined" ? true : val;
+}
+
+/**
+ * parse attrs from object
+ *
+ * @param {Object} obj
+ * @returns {Stirng}
+ */
+function getAttr(obj) {
+ var attr = "";
+ for (var key in obj) {
+ if (key) {
+ attr += " " + key + '="' + obj[key] + '"';
+ }
+ }
+ return attr;
+}
+
+/**
+ * @param {String} url
+ * @returns {String}
+ */
+function prepHTTP(url) {
+ if (url.substring(0, 4) !== "http" && url.substring(0, 2) !== "//") {
+ return "http://" + url;
+ }
+ return url;
+}
+
+/**
+ * @param {String} url
+ * @returns {String}
+ */
+function removeHTTP(url) {
+ return url.replace(re.http, "");
+}
+
+var tagsToReplace = {
+ "&": "&amp;",
+ "<": "&lt;",
+ ">": "&gt;",
+};
+
+/**
+ * Replace tag if should be replace
+ *
+ * @param {String} tag
+ * @returns {String}
+ */
+function replaceTag(tag) {
+ return tagsToReplace[tag] || tag;
+}
+
+/**
+ * Make string safe by replacing html tag
+ *
+ * @param {String} str
+ * @returns {String}
+ */
+function safe_tags_replace(str) {
+ return str.replace(/[&<>]/g, replaceTag);
+}
+
+/**
+ * return an instance of AutoLink
+ *
+ * @param {String} string
+ * @param {Object} options
+ * @returns {Object}
+ */
+function autoLink(string, options) {
+ return new AutoLink(string, options).parse();
+}
+
+//export default autoLink
diff --git a/src/quoted-printable.js b/src/quoted-printable.js
new file mode 100644
index 0000000..87f2329
--- /dev/null
+++ b/src/quoted-printable.js
@@ -0,0 +1,153 @@
+/*! https://mths.be/quoted-printable v<%= version %> by @mathias | MIT license */
+;(function(root) {
+
+ // Detect free variables `exports`.
+ var freeExports = typeof exports == 'object' && exports;
+
+ // Detect free variable `module`.
+ var freeModule = typeof module == 'object' && module &&
+ module.exports == freeExports && module;
+
+ // Detect free variable `global`, from Node.js or Browserified code, and use
+ // it as `root`.
+ var freeGlobal = typeof global == 'object' && global;
+ if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
+ root = freeGlobal;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ var stringFromCharCode = String.fromCharCode;
+ var decode = function(input) {
+ return input
+ // https://tools.ietf.org/html/rfc2045#section-6.7, rule 3:
+ // “Therefore, when decoding a `Quoted-Printable` body, any trailing white
+ // space on a line must be deleted, as it will necessarily have been added
+ // by intermediate transport agents.”
+ .replace(/[\t\x20]$/gm, '')
+ // Remove hard line breaks preceded by `=`. Proper `Quoted-Printable`-
+ // encoded data only contains CRLF line endings, but for compatibility
+ // reasons we support separate CR and LF too.
+ .replace(/=(?:\r\n?|\n|$)/g, '')
+ // Decode escape sequences of the form `=XX` where `XX` is any
+ // combination of two hexidecimal digits. For optimal compatibility,
+ // lowercase hexadecimal digits are supported as well. See
+ // https://tools.ietf.org/html/rfc2045#section-6.7, note 1.
+ .replace(/=([a-fA-F0-9]{2})/g, function($0, $1) {
+ var codePoint = parseInt($1, 16);
+ return stringFromCharCode(codePoint);
+ });
+ };
+
+ var handleTrailingCharacters = function(string) {
+ return string
+ .replace(/\x20$/, '=20') // Handle trailing space.
+ .replace(/\t$/, '=09') // Handle trailing tab.
+ };
+
+ var regexUnsafeSymbols = /<%= unsafeSymbols %>/g;
+ var encode = function(string) {
+
+ // Encode symbols that are definitely unsafe (i.e. unsafe in any context).
+ var encoded = string.replace(regexUnsafeSymbols, function(symbol) {
+ if (symbol > '\xFF') {
+ throw RangeError(
+ '`quotedPrintable.encode()` expects extended ASCII input only. ' +
+ 'Don\u2019t forget to encode the input first using a character ' +
+ 'encoding like UTF-8.'
+ );
+ }
+ var codePoint = symbol.charCodeAt(0);
+ var hexadecimal = codePoint.toString(16).toUpperCase();
+ return '=' + ('0' + hexadecimal).slice(-2);
+ });
+
+ // Limit lines to 76 characters (not counting the CRLF line endings).
+ var lines = encoded.split(/\r\n?|\n/g);
+ var lineIndex = -1;
+ var lineCount = lines.length;
+ var result = [];
+ while (++lineIndex < lineCount) {
+ var line = lines[lineIndex];
+ // Leave room for the trailing `=` for soft line breaks.
+ var LINE_LENGTH = 75;
+ var index = 0;
+ var length = line.length;
+ while (index < length) {
+ var buffer = encoded.slice(index, index + LINE_LENGTH);
+ // If this line ends with `=`, optionally followed by a single uppercase
+ // hexadecimal digit, we broke an escape sequence in half. Fix it by
+ // moving these characters to the next line.
+ if (/=$/.test(buffer)) {
+ buffer = buffer.slice(0, LINE_LENGTH - 1);
+ index += LINE_LENGTH - 1;
+ } else if (/=[A-F0-9]$/.test(buffer)) {
+ buffer = buffer.slice(0, LINE_LENGTH - 2);
+ index += LINE_LENGTH - 2;
+ } else {
+ index += LINE_LENGTH;
+ }
+ result.push(buffer);
+ }
+ }
+
+ // Encode space and tab characters at the end of encoded lines. Note that
+ // with the current implementation, this can only occur at the very end of
+ // the encoded string — every other line ends with `=` anyway.
+ var lastLineLength = buffer.length;
+ if (/[\t\x20]$/.test(buffer)) {
+ // There’s a space or a tab at the end of the last encoded line. Remove
+ // this line from the `result` array, as it needs to change.
+ result.pop();
+ if (lastLineLength + 2 <= LINE_LENGTH + 1) {
+ // It’s possible to encode the character without exceeding the line
+ // length limit.
+ result.push(
+ handleTrailingCharacters(buffer)
+ );
+ } else {
+ // It’s not possible to encode the character without exceeding the line
+ // length limit. Remvoe the character from the line, and insert a new
+ // line that contains only the encoded character.
+ result.push(
+ buffer.slice(0, lastLineLength - 1),
+ handleTrailingCharacters(
+ buffer.slice(lastLineLength - 1, lastLineLength)
+ )
+ );
+ }
+ }
+
+ // `Quoted-Printable` uses CRLF.
+ return result.join('=\r\n');
+ };
+
+ var quotedPrintable = {
+ 'encode': encode,
+ 'decode': decode,
+ 'version': '<%= version %>'
+ };
+
+ // Some AMD build optimizers, like r.js, check for specific condition patterns
+ // like the following:
+ if (
+ typeof define == 'function' &&
+ typeof define.amd == 'object' &&
+ define.amd
+ ) {
+ define(function() {
+ return quotedPrintable;
+ });
+ } else if (freeExports && !freeExports.nodeType) {
+ if (freeModule) { // in Node.js, io.js, or RingoJS v0.8.0+
+ freeModule.exports = quotedPrintable;
+ } else { // in Narwhal or RingoJS v0.7.0-
+ for (var key in quotedPrintable) {
+ quotedPrintable.hasOwnProperty(key) && (freeExports[key] = quotedPrintable[key]);
+ }
+ }
+ } else { // in Rhino or a web browser
+ root.quotedPrintable = quotedPrintable;
+ }
+
+}(this));