Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Master #1

Merged
merged 5 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ yarn-error.log*

# vercel
.vercel

#misc
/.alt-components/
/.preview-compoenents/
.testUsers
23 changes: 13 additions & 10 deletions api-lib/auth/passport.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
import {
findUserByLogin,
UNSAFE_findUserForAuth,
} from '@/api-lib/db';
import { findUserByLoginAndPassword, UNSAFE_findUserForAuth } from '@/api-lib/db';
import passport from 'passport';
import { Strategy as LocalStrategy } from 'passport-local';
import { getMongoDb } from '../mongodb';

passport.serializeUser((user, done) => {
done(null, user._id);
});

// passport#160
passport.deserializeUser((req, id, done) => {
UNSAFE_findUserForAuth(req.db, id).then(
(user) => done(null, user),
(err) => done(err)
);
getMongoDb().then((db) => {
UNSAFE_findUserForAuth(db, id).then(
(user) => done(null, user),
(err) => done(err)
);
});
});

passport.use(
new LocalStrategy(
{ usernameField: 'login', passReqToCallback: true },
async (req, login, password, done) => {
const user = await findUserByLogin(req.db, login, password);
const db = await getMongoDb();

const user = await findUserByLoginAndPassword(db, login, password);

if (user) done(null, user);
else done(null, false, { message: 'Email or password is incorrect' });
else done(null, false, { message: 'Login or Password is incorrect' });
}
)
);
Expand Down
12 changes: 6 additions & 6 deletions api-lib/constants.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
export const ValidateProps = {
user: {
username: { type: 'string', minLength: 4, maxLength: 20 },
firstName: { type: 'string', minLength: 1, maxLength: 20 },
lastName: {type: 'string', minLength: 1, maxLength: 20 },
password: { type: 'string', minLength: 8 },
username: { type: 'string', minLength: 2, maxLength: 20 },
password: { type: 'string', minLength: 8, maxLength: 64 },
confirmPassword: { type: 'string', minLength: 8, maxLength: 64 },
email: { type: 'string', minLength: 1 },
bio: { type: 'string', minLength: 0, maxLength: 160 },
},
post: {
content: { type: 'string', minLength: 1, maxLength: 280 },
title: { type: 'string', minLength: 1, maxLength: 30},
people: { type: 'array', }
}
};
};
113 changes: 113 additions & 0 deletions api-lib/db/bunny.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import date from 'date-and-time';
import queryString from 'querystring';
import crypto from 'crypto';

import { fetcher } from '@/lib/fetch';

export async function signPost(post, member, userIp) {
const expires = Date.now() + (4 * 60 *60 * 1000);

post.promoVideo = `https://${process.env.BUNNY_PROMO_PULL_ZONE}/${post.promoVideoId}/play_360p.mp4`;

post.promoStream = `https://iframe.mediadelivery.net/embed/71837/${post.promoVideoId}?autoplay=false`;

if (member) {
const streamToHash = process.env.BUNNY_MEDIA_AUTH_TOKEN + post.mainVideoId + expires;
const streamToken = crypto.createHash('sha256').update(streamToHash).digest('hex');
post.mainStream = `https://iframe.mediadelivery.net/embed/28034/${post.mainVideoId}?token=${streamToken}&expires=${expires}&autoplay=false`;
// post.mainStream = await signUrl(streamUrl, process.env.BUNNY_MEDIA_AUTH_TOKEN, 7200, userIp, true, streamUrl, '', '');

const downloadUrl = `https://${process.env.BUNNY_MEDIA_PULL_ZONE}/${post.mainVideoId}/original`;

post.mainDownload = await signUrl(downloadUrl, process.env.BUNNY_MEDIA_AUTH_TOKEN, 7200, '', false, '/', '', '');
}
post._id = String(post._id);
post.publishDate = date.format(new Date(post.publishDate), 'MMM DD, YYYY');
post.shootDate = date.format(new Date(post.shootDate), 'MMM DD, YYYY');
post.lastUpdated = date.format(new Date(post.lastUpdated), 'MMM DD, YYYY');

return post;
}

export async function getBunnyInfo(libId, vidId, apiKey) {
const url = `https://video.bunnycdn.com/library/${libId}/videos/${vidId}`;
const options = {
method: 'GET',
headers: {
accept: 'application/json',
AccessKey: apiKey
}
}
const info = await fetcher(url, options);
return info;
};

export async function encodeVideo(libId, vidId, apiKey) {
const encode = await fetcher(`https://video.bunnycdn.com/library/${libId}/videos/${vidId}/reencode`, {
method: 'POST',
headers: {
accept: 'application/json',
AccessKey: apiKey
}
})
return encode;
}

export async function addCountries(url, a, b) {
var tempUrl = url;
if (a != null) {
var tempUrlOne = new URL(tempUrl);
tempUrl += (( tempUrlOne.search == "" ) ? "?" : "&") + "token_countries=" + a;
}
if (b != null) {
var tempUrlTwo = new URL(tempUrl);
tempUrl += ((tempUrlTwo.search == "") ? "?" : "&") + "token_countries_blocked=" + b;
}
return tempUrl;
}

export async function signUrl(url, securityKey, expirationTime, userIp, isDirectory, pathAllowed, countriesAllowed, countriesBlocked){
/*
url: CDN URL w/o the trailing '/' - exp. http://test.b-cdn.net/file.png
securityKey: Security token found in your pull zone
expirationTime: Authentication validity (default. 86400 sec/24 hrs)
userIp: Optional parameter if you have the User IP feature enabled
isDirectory: Optional parameter - "true" returns a URL separated by forward slashes (exp. (domain)/bcdn_token=...)
pathAllowed: Directory to authenticate (exp. /path/to/images)
countriesAllowed: List of countries allowed (exp. CA, US, TH)
countriesBlocked: List of countries blocked (exp. CA, US, TH)
*/
var parameterData = "", parameterDataUrl = "", signaturePath = "", hashableBase = "", token = "";
var expires = Math.floor(new Date() / 1000) + expirationTime;
var url = await addCountries(url, countriesAllowed, countriesBlocked);
var parsedUrl = new URL(url);
var parameters = (new URL(url)).searchParams;
if (pathAllowed != "") {
signaturePath = pathAllowed;
parameters.set("token_path", signaturePath);
} else {
signaturePath = decodeURIComponent(parsedUrl.pathname);
}
parameters.sort();
if (Array.from(parameters).length > 0) {
parameters.forEach(function(value, key) {
if (value == "") {
return;
}
if (parameterData.length > 0) {
parameterData += "&";
}
parameterData += key + "=" + value;
parameterDataUrl += "&" + key + "=" + queryString.escape(value);

});
}
hashableBase = securityKey + signaturePath + expires + ((userIp != null) ? userIp : "") + parameterData;
token = Buffer.from(crypto.createHash("sha256").update(hashableBase).digest()).toString("base64");
token = token.replace(/\n/g, "").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
if (isDirectory) {
return parsedUrl.protocol+ "//" + parsedUrl.host + "/bcdn_token=" + token + parameterDataUrl + "&expires=" + expires + parsedUrl.pathname;
} else {
return parsedUrl.protocol + "//" + parsedUrl.host + parsedUrl.pathname + "?token=" + token + parameterDataUrl + "&expires=" + expires;
}
}
35 changes: 24 additions & 11 deletions api-lib/db/comment.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
export async function findComments(db, postId, from, limit) {
import { ObjectId } from 'mongodb';
import { dbProjectionUsers } from '.';

export async function findComments(db, postId, before, limit = 10) {
return db
.collection('comments')
.find({
postId,
...(from && {
createdAt: {
$lte: from,
.aggregate([
{
$match: {
postId: new ObjectId(postId),
...(before && { createdAt: { $lt: before } }),
},
},
{ $sort: { _id: -1 } },
{ $limit: limit },
{
$lookup: {
from: 'users',
localField: 'creatorId',
foreignField: '_id',
as: 'creator',
},
}),
})
.sort({ $natural: -1 })
.limit(limit)
},
{ $unwind: '$creator' },
{ $project: dbProjectionUsers('creator.') },
])
.toArray();
}

export async function insertComment(db, postId, { content, creatorId }) {
const comment = {
content,
postId,
postId: new ObjectId(postId),
creatorId,
createdAt: new Date(),
};
Expand Down
92 changes: 92 additions & 0 deletions api-lib/db/epoch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import isEmail from 'validator/lib/isEmail';

import { slugUsername } from '@/api-lib/validators';
import normalizeEmail from 'validator/lib/normalizeEmail';
import { fetcher } from '@/lib/fetch';
import { searchApi, cancelApi } from '@/lib/user/utils';

import { insertUser, updateUserById } from '@/api-lib/db';

export async function epochCancel(db, user) {
let { MemberId } = user?.epoch?.Customer;
let cancelRes = await fetcher(cancelApi(MemberId));

if(cancelRes?.Response?.Cancel?.Response == 'Success') {
let searchRes = await fetcher(searchApi('member_id', MemberId));
const { Customer } = searchRes?.Data[0];

const updatedUser = await updateUserById(db, user._id, {
... ({ epoch: {
Customer,
}}),
... ({ lastChecked: new Date().toJSON() }),
... ({ subscribed: user.creator ? true : ((Customer.NextBillDate || Customer.PasswordRemovalDate) < new Date() ? true : false)}),
});
return { user: updatedUser };
} else {
return cancelRes;
}
}

export async function epochCheck(db, user) {
let data;
if(user?.epoch?.Customer?.MemberId) data = await fetcher(searchApi('member_id', user.epoch.Customer.MemberId))
if(!data?.Data) data = await fetcher(searchApi('email', user.email));
if(!data?.Data) data = await fetcher(searchApi('username', user.username));

if(data.Data) {
const { Customer } = data?.Data[0];

let updatedUser = await updateUserById(db, user._id, {
... ( { epoch: {
Customer,
}}),
... ({ lastChecked: new Date().toJSON() }),
... ({ subscribed: (Date.parse(Customer.NextBillDate) > new Date()) || (Date.parse(Customer.PasswordRemovalDate) > new Date()) ? true : false }),
});
return { user: updatedUser};
} else {
let updatedUser = await updateUserById(db, user._id, {
... ( { lastChecked: new Date().toJSON() }),
... ({ subscribed: false }),
});
return { user: updatedUser};
}
}

export async function epochLogin(db, login, password) {

const epochConnect = isEmail(login) ? searchApi('email', login) : searchApi('username', login);
const data = await fetcher(epochConnect);

if(data.ErrorResponse) {
return data;
} else {
const { Customer } = data?.Data[0];
if(password === Customer?.Password) {

const user = await insertUser(db, {
email: normalizeEmail(Customer.Email),
username: slugUsername(Customer.Username),
lastChecked: new Date().toJSON(),
epoch: {
Customer
},
subscribed: (Customer.NextBillDate || Customer.PasswordRemovalDate < new Date() ? true : false),
originalPassword: password,
});
return user;
} else {
return 'match';
}
}
}

export async function epochEmail(email) {
let data = await fetcher(searchApi('email', email));
if (data.ErrorResponse) {
let data = await fetcher(searchApi('email', await normalizeEmail(email)));
return data;
}
return data;
}
6 changes: 0 additions & 6 deletions api-lib/db/filters.js

This file was deleted.

7 changes: 4 additions & 3 deletions api-lib/db/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './user';
export * from './sqlUser';
export * from './post';
export * from './token';
export * from './filters';
export * from './site';
export * from './site';
export * from './tag';
export * from './epoch';
export * from './bunny';
Loading