Initial commit.
This commit is contained in:
commit
9d4d264a09
6 changed files with 1215 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
sendgrid.env
|
||||
messages/
|
||||
node_modules/
|
22
lib/MimeHeader.js
Normal file
22
lib/MimeHeader.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
class MimeHeader {
|
||||
constructor(message) {
|
||||
if ( message.indexOf(':') === -1 ) {
|
||||
throw new TypeError("Invalid header.");
|
||||
}
|
||||
this.rawMessage = message;
|
||||
}
|
||||
|
||||
get key() {
|
||||
return this.rawMessage.split(':')[0].trim();
|
||||
}
|
||||
|
||||
get rawValue() {
|
||||
return this.rawMessage.slice(this.rawMessage.indexOf(':'));
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.rawMessage;
|
||||
}
|
||||
}
|
||||
|
||||
export default MimeHeader;
|
60
lib/MimeMessage.js
Normal file
60
lib/MimeMessage.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
import MimeHeader from "./MimeHeader";
|
||||
|
||||
class MimeMessage {
|
||||
constructor(message) {
|
||||
this.headers = [];
|
||||
this.body = "";
|
||||
let messageLines = message.split('\r\n');
|
||||
let inHeaders = true;
|
||||
let currentMessageLine = 0;
|
||||
let currentHeader = messageLines[currentMessageLine];
|
||||
currentMessageLine++;
|
||||
while (inHeaders) {
|
||||
if (messageLines[currentMessageLine] === "") {
|
||||
inHeaders = false;
|
||||
this.headers.push(new MimeHeader(currentHeader));
|
||||
} else if (messageLines[currentMessageLine].match(/^\s/)) {
|
||||
currentHeader = `${currentHeader}\r\n${messageLines[currentMessageLine]}`;
|
||||
} else {
|
||||
this.headers.push(new MimeHeader(currentHeader));
|
||||
currentHeader = `${messageLines[currentMessageLine]}`;
|
||||
}
|
||||
currentMessageLine++;
|
||||
}
|
||||
|
||||
this.body = messageLines.slice(currentMessageLine).join("\r\n");
|
||||
}
|
||||
|
||||
prependHeader(header) {
|
||||
if ( header instanceof MimeHeader ) {
|
||||
this.headers.unshift(header);
|
||||
} else if ( typeof header === "string" ) {
|
||||
this.headers.unshift(new MimeHeader(header) );
|
||||
} else {
|
||||
throw new TypeError("Invalid object passed to prependHeader");
|
||||
}
|
||||
}
|
||||
|
||||
getFirstHeaderOf(key) {
|
||||
return this.headers.find((header) => header.key.toLowerCase() === key.toLowerCase());
|
||||
}
|
||||
|
||||
getAllHeaderOf(key) {
|
||||
return this.headers.filter((header) => header.key.toLowerCase() === key.toLowerCase());
|
||||
}
|
||||
|
||||
removeFirstHeaderOf(key) {
|
||||
let indexOfFirst = this.headers.findIndex((header) => header.key.toLowerCase() === key.toLowerCase());
|
||||
this.headers = [...this.headers.slice(0, indexOfFirst), ...this.headers.slice(indexOfFirst+1)];
|
||||
}
|
||||
|
||||
removeAllHeaderOf(key) {
|
||||
this.headers = this.headers.filter((header) => header.key.toLowerCase() !== key.toLowerCase());
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `${this.headers.map((header) => header.toString()).join("\r\n")}\r\n\r\n${this.body}`;
|
||||
}
|
||||
}
|
||||
|
||||
export default MimeMessage;
|
1034
package-lock.json
generated
Normal file
1034
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
9
package.json
Normal file
9
package.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"@sendgrid/mail": "^8.1.4",
|
||||
"body-parser": "^1.20.3",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"express": "^4.21.2",
|
||||
"formidable": "^3.5.2"
|
||||
}
|
||||
}
|
87
server.js
Normal file
87
server.js
Normal file
|
@ -0,0 +1,87 @@
|
|||
import express from "express";
|
||||
const app = express();
|
||||
|
||||
import formidable from "formidable";
|
||||
import fs from "node:fs";
|
||||
|
||||
import cookieParser from 'cookie-parser';
|
||||
|
||||
app.use(cookieParser());
|
||||
|
||||
app.post('/sendgrid/ingress', (req, res) => {
|
||||
const form = formidable({});
|
||||
|
||||
form.parse(req, (err, fields, files) => {
|
||||
var message = "";
|
||||
if ( fields.email ) {
|
||||
if ( typeof fields.email === "string") {
|
||||
message = fields.email;
|
||||
} else {
|
||||
message = fields.email.join("");
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(`messages/${new Date().toISOString()}.eml`, message);
|
||||
fs.writeFileSync(`messages/${new Date().toISOString()}.json`, JSON.stringify(fields));
|
||||
res.status(204);
|
||||
res.end();
|
||||
})
|
||||
});
|
||||
|
||||
app.post('/mail/login', (req, res) => {
|
||||
// TODO: Actual proper login stuffs.
|
||||
res.cookie("authenticated", "true", {maxAge: 86_400_000});
|
||||
res.redirect("/static/jmapjs");
|
||||
})
|
||||
|
||||
// JMAP implementation.
|
||||
|
||||
app.all("/.well-known/jmap", (req, res) => {
|
||||
res.redirect("/jmap/session");
|
||||
});
|
||||
|
||||
// https://jmap.io/spec-core.html#the-jmap-session-resource
|
||||
// TODO: Authenticated
|
||||
app.get("/jmap/session", (req, res) => {
|
||||
if ( req.cookies.authenticated == "true" )
|
||||
res.json({
|
||||
"capabilities": {
|
||||
"urn:ietf:params:jmap:core": {
|
||||
"maxSizeUpload": 50000000,
|
||||
"maxConcurrentUpload": 8,
|
||||
"maxSizeRequest": 10000000,
|
||||
"maxConcurrentRequests": 8,
|
||||
"maxCallsInRequest": 32,
|
||||
"maxObjectsInGet": 256,
|
||||
"maxObjectsInSet": 128,
|
||||
"collationAlgorithms": [
|
||||
"i;ascii-numeric",
|
||||
"i;ascii-casemap",
|
||||
"i;unicode-casemap"
|
||||
]
|
||||
},
|
||||
},
|
||||
"accounts": {
|
||||
"andrew@andrewpietila.com": {
|
||||
"name": "andrew@andrewpietila.com",
|
||||
isPersonal: true,
|
||||
isReadOnly: false,
|
||||
accountCapabilities: {}
|
||||
}
|
||||
},
|
||||
"primaryAccounts": {
|
||||
},
|
||||
"username": "andrew@andrewpietila.com",
|
||||
"apiUrl": "https://andrewpietila.com/api/jmap/api/",
|
||||
"downloadUrl": "https://andrewpietila.com/api/jmap/download/{accountId}/{blobId}/{name}?accept={type}",
|
||||
"uploadUrl": "https://andrewpietila.com/api/jmap/upload/{accountId}/",
|
||||
"eventSourceUrl": "https://andrewpietila.com/api/jmap/eventsource/?types={types}&closeafter={closeafter}&ping={ping}",
|
||||
"state": "75128aab4b1b"
|
||||
});
|
||||
else {
|
||||
res.status(404);
|
||||
res.end();
|
||||
}
|
||||
})
|
||||
|
||||
app.listen(8080);
|
Loading…
Add table
Reference in a new issue