Skip to content

Commit

Permalink
Added custom domain support (commented out SSL, it is REALLY complica…
Browse files Browse the repository at this point in the history
…ted)

Fixed deep link lib import
Actually update Amazon AWS SDK config updates
Add middleware for custom domains
Cleanup code a bit
  • Loading branch information
NavidK0 committed Oct 14, 2020
1 parent 6f671a2 commit e0d5276
Show file tree
Hide file tree
Showing 10 changed files with 600 additions and 84 deletions.
4 changes: 2 additions & 2 deletions server/functions/Analytics/link.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {DeepLinker} from "nc-deeplink";
const DeepLink = require("nc-deeplink");

const mongoose = require('mongoose');
const Link = mongoose.model('Link');
Expand All @@ -19,7 +19,7 @@ module.exports = async (req, res) => {

if (link.useDeepLink) {
const userAgent = req.get('user-agent');
const deepLink = DeepLinker.parseDeepLink(link.url, userAgent);
const deepLink = DeepLink.DeepLinker.parseDeepLink(link.url, userAgent);

return res.redirect(deepLink);
} else {
Expand Down
28 changes: 15 additions & 13 deletions server/functions/Profile/update.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
const mongoose = require('mongoose');

const Profile = mongoose.model('Profile');

module.exports = (req, res) => {
req.user.active_profile.image_url = req.body.image_url || null;
if(req.body.headline) req.user.active_profile.headline = req.body.headline;
if(req.body.subtitle) req.user.active_profile.subtitle = req.body.subtitle;
if(req.body.handle) req.user.active_profile.handle = req.body.handle;
if(req.body.visibility) req.user.active_profile.visibility = req.body.visibility;
if(typeof req.body.custom_css != 'undefined') req.user.active_profile.custom_css = req.body.custom_css || '';
if(typeof req.body.custom_html != 'undefined') req.user.active_profile.custom_html = req.body.custom_html || '';
req.user.active_profile.image_url = req.body.image_url || null;
if (req.body.headline) req.user.active_profile.headline = req.body.headline;
if (req.body.subtitle) req.user.active_profile.subtitle = req.body.subtitle;
if (req.body.handle) req.user.active_profile.handle = req.body.handle;
if (req.body.visibility) req.user.active_profile.visibility = req.body.visibility;
if (typeof req.body.custom_css != 'undefined') req.user.active_profile.custom_css = req.body.custom_css || '';
if (typeof req.body.custom_html != 'undefined') req.user.active_profile.custom_html = req.body.custom_html || '';

if (req.body.custom_domain) {
req.user.active_profile.custom_domain = req.body.custom_domain;
}

req.user.active_profile.save((err, profile) => {
if(err) return res.send(err);
res.send(profile);
})
req.user.active_profile.save((err, profile) => {
if (err) return res.send(err);
res.send(profile);
})
}
61 changes: 30 additions & 31 deletions server/functions/User/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,37 @@ const User = mongoose.model('User');
const Profile = mongoose.model('Profile');

module.exports = (req, res) => {
if(!req.body.email) return res.status(400).send('Missing email');
if(!req.body.password) return res.status(400).send('Missing password');
User.findOne({ email : req.body.email }, function(err, user) {
if (err) return res.status(500).send(err);
if (user) return res.status(404).send('User with that email address already exists');
bcrypt.hash(req.body.password, null, null, function (err, hash) {
if (err) return res.status(500).send(err);
new User({
name: req.body.name || null,
email: req.body.email || null,
password: hash,
hash: md5(req.body.email)
}).save(function (err, user) {

new Profile({parent: user._id, handle: req.body.handle || user._id }).save(function(err, profile) {
user.active_profile = profile._id;
user.save(function (err, user) {
if (err) return res.send(err);
return res.status(201).json({
user: user,
active_profile: profile,
token: jwt.sign(
{
email: user.email,
}, global.config.secret, {
expiresIn: '168h'
}
)
});
});
});
if (!req.body.email) return res.status(400).send('Missing email');
if (!req.body.password) return res.status(400).send('Missing password');
User.findOne({email: req.body.email}, function (err, user) {
if (err) return res.status(500).send(err);
if (user) return res.status(404).send('User with that email address already exists');
bcrypt.hash(req.body.password, null, null, function (err, hash) {
if (err) return res.status(500).send(err);
new User({
name: req.body.name || null,
email: req.body.email || null,
password: hash,
hash: md5(req.body.email)
}).save(function (err, user) {
new Profile({parent: user._id, handle: req.body.handle || user._id}).save(function (err, profile) {
user.active_profile = profile._id;
user.save(function (err, user) {
if (err) return res.send(err);
return res.status(201).json({
user: user,
active_profile: profile,
token: jwt.sign(
{
email: user.email,
}, global.config.secret, {
expiresIn: '168h'
}
)
});
});
});
});
});
});
}
10 changes: 3 additions & 7 deletions server/functions/User/request-password-reset.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
const bcrypt = require('bcrypt-nodejs');
const jwt = require('jsonwebtoken');
const mongoose = require('mongoose');
const AWS = require('aws-sdk');

const User = mongoose.model('User');

let senderEmailAddress = global.config.senderEmailAddress;
let awsRegion = global.config.aws.region;
let awsAccessKey = global.config.aws.accessKey;
let awsSecretKey = global.config.aws.secretKey;
let senderEmailAddress = global.config.aws.senderEmailAddress;

module.exports = (req, res) => {
if (!req.body.email)
Expand Down Expand Up @@ -36,7 +32,7 @@ async function sendPasswordResetEmail(email) {
email,
passwordReset: true
},
global.config.email,
global.config.secret,
{
expiresIn: '60m'
}
Expand Down Expand Up @@ -75,7 +71,7 @@ Note: Do not reply to this email, as there is no inbox for it.`
Data: 'Password Reset Request for SingleLink'
}
},
Source: global.config.senderEmailAddress
Source: senderEmailAddress
};

await new AWS.SES().sendEmail(emailParams).promise();
Expand Down
47 changes: 43 additions & 4 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ global.config = require('./config');

global.mongodb = true;

AWS.config.update({
region: config.aws.region,
credentials: {
accessKeyId: config.aws.accessKey,
secretAccessKey: config.aws.secretKey
},
apiVersion: '2010-12-01'
});

mongoose.connect(global.config.database,
{
useNewUrlParser: true
Expand All @@ -23,6 +32,7 @@ mongoose.connect(global.config.database,
const app = express();
const environment = process.env.NODE_ENV || 'development';
let port;
let sslPort;

const emailRateLimiter = rateLimit({
windowMs: 180 * 60 * 1000, // 180 minutes
Expand All @@ -34,24 +44,53 @@ app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use("/user/request-password-reset", emailRateLimiter);

app.use("/user/request-password-reset", emailRateLimiter);
port = process.env.API_PORT || config.port || 80;

app.get('/', require('./functions/Misc/status'));
sslPort = process.env.API_SSL_PORT || config.sslPort || 443;

const User = require('./models/User');
const Profile = require('./models/Profile');
const Link = require('./models/Link');
const Theme = require('./models/Theme');
const Visit = require('./models/Visit');

app.use(require('./middleware/custom-domains'));
app.use('/user', require('./functions/User'));
app.use('/profile', require('./functions/Profile'));
app.use('/link', require('./functions/Link'));
app.use('/theme', require('./functions/Theme'));
app.use('/analytics', require('./functions/Analytics'))

app.get('/', require('./functions/Misc/status'));

app.listen(port, () => {
console.log(`🔗 Singlelink API listening on port ${port}`)
})
});

app.listen(sslPort, () => {
console.log(`🔗 Singlelink API listening on SSL port 443`)
});


// const store = require('greenlock-storage-s3').create({
// accessKeyId: config.s3Bucket.accessKey,
// secretAccessKey: config.s3Bucket.secretKey,
// bucketRegion: config.s3Bucket.endPoint,
// bucketName: config.s3Bucket.bucketName,
// configDir: 'acme/',
// accountsDir: 'accounts/',
// debug: true
// });
//
// const greenlock = require('greenlock-express').init({
// packageRoot: __dirname,
// store: store,
// maintainerEmail: config.contactEmail,
// cluster: true
// }).serve(app);
//
// greenlock.manager.defaults({
// subscriberEmail: "mycompany@example.com",
// agreeToTerms: true
// });
31 changes: 14 additions & 17 deletions server/middleware/auth.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
// functions/middleware/auth.js

const mongoose = require('mongoose');
const bcrypt = require('bcrypt-nodejs');
const jwt = require('jsonwebtoken');

const config = global.config;

const User = mongoose.model('User');
const Profile = mongoose.model('Profile');

module.exports = function(req, res, next) {
const response = res;
if(req.query.token) req.body.token = req.query.token;
if(!req.body.token) return res.status(400).send('Missing token');
jwt.verify(req.body.token, config.secret, function(err, decoded) {
if(err) return res.status(400).send(err);
if(!decoded.email) return res.status(400).send('Unable to verify user, returning to sign in');
User.findOne({email: decoded.email})
.populate('active_profile')
.exec(function(err, user) {
if(err) res.send(err);
req.user = user;
next();
});
})
module.exports = function (req, res, next) {
if (req.query.token) req.body.token = req.query.token;
if (!req.body.token) return res.status(400).send('Missing token');
jwt.verify(req.body.token, config.secret, function (err, decoded) {
if (err) return res.status(400).send(err);
if (!decoded.email) return res.status(400).send('Unable to verify user, returning to sign in');
User.findOne({email: decoded.email})
.populate('active_profile')
.exec(function (err, user) {
if (err) res.send(err);
req.user = user;
next();
});
})
}
51 changes: 51 additions & 0 deletions server/middleware/custom-domains.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const mongoose = require('mongoose');
const config = global.config;

const Profile = mongoose.model('Profile');

module.exports = async function (req, res, next) {
let host = req.hostname;
let clientDomain = config.clientDomain;

let profile = await Profile.findOne({custom_domain: host}).exec();

if (!profile || profile.visibility === "unpublished")
return next();

let user = profile.parent;
let handle = profile.handle;

let url = `${clientDomain}/u/${handle}`;

if (user) {

res.status(200).send(`<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<iframe
src='${url}'
style="
position: fixed;
top: 0;
bottom: 0;
right: 0;
width: 100%;
border: none;
margin: 0;
padding: 0;
overflow: hidden;
z-index: 999999;
height: 100%;
">
</iframe>
</body>
</html>`);

return;
}

return next();
}
7 changes: 4 additions & 3 deletions server/models/Profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,16 @@ const ProfileSchema = new mongoose.Schema({
},
custom_css: String,
custom_html: String,
custom_domain: String,
theme: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Theme',
},
});

ProfileSchema.virtual('permissions').get(function() {
if(this.members) return this.members.push(this.parent);
return [this.parent];
ProfileSchema.virtual('permissions').get(function () {
if (this.members) return this.members.push(this.parent);
return [this.parent];
});

module.exports = mongoose.model('Profile', ProfileSchema);
Loading

0 comments on commit e0d5276

Please sign in to comment.