diff --git a/README.md b/README.md index fc6b559..8599b1f 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,6 @@ With this Glitch starter project, you can create a bot that anyone [in the fediverse](https://en.wikipedia.org/wiki/Fediverse) can follow. This project is [in early development](https://github.com/botwiki/glitch-fediverse-bot/issues) with more features coming. -To automate your bot, set up a free service like [cron-job.org](https://cron-job.org/en/), [Uptime Robot](https://uptimerobot.com/), or [a similar one](https://www.google.com/search?q=free+web+cron) to wake up your bot [every 25+ minutes](https://support.glitch.com/t/a-simple-twitter-bot-template/747/16). Use `https://YOUR_PROJECT_NAME.glitch.me/BOT_ENDPOINT` as a URL to which to send the HTTP request. (`BOT_ENDPOINT` is set in your `.env` file.) - ## Bot administration @@ -17,7 +15,7 @@ You can log into the admin panel by going to `YOUR_PROJECT_NAME.glitch.me/admin` ## Bot logic (the back end) -Your bot's logic is inside the `routes/bot-endpoint.js` file. This is the code that runs when you access your bot's endpoint, as defined inside the `.env` file. See the `examples` folder for some examples of what your bot can do. +*TBD* ## The look of your bot's page (the front end) diff --git a/app.js b/app.js index e2307e4..7bf4c53 100644 --- a/app.js +++ b/app.js @@ -1,78 +1,78 @@ -var path = require('path'), - express = require('express'), - session = require('express-session'), - SQLiteStore = require('connect-sqlite3')(session), - exphbs = require('express-handlebars'), - bodyParser = require('body-parser'), - pubSubHubbub = require('pubsubhubbub'), - sassMiddleware = require('node-sass-middleware'), - babelify = require('express-babelify-middleware'), - helpers = require(__dirname + '/helpers/general.js'), - db = require(__dirname + '/helpers/db.js'), - app = express(); +const path = require( 'path' ), + express = require( 'express' ), + session = require( 'express-session' ), + SQLiteStore = require( 'connect-sqlite3' )( session ), + exphbs = require( 'express-handlebars' ), + bodyParser = require( 'body-parser' ), + pubSubHubbub = require( 'pubsubhubbub' ), + sassMiddleware = require( 'node-sass-middleware' ), + babelify = require( 'express-babelify-middleware' ), + helpers = require( __dirname + '/helpers/general.js' ), + db = require( __dirname + '/helpers/db.js' ), + app = express(); -app.use(express.static('public')); +app.use( express.static( 'public' ) ); -app.use(bodyParser.json({ +app.use( bodyParser.json( { type: 'application/activity+json' -})); +} ) ); -app.use(bodyParser.urlencoded({ +app.use( bodyParser.urlencoded( { extended: true -})); +} ) ); -app.use(session({ +app.use( session( { store: new SQLiteStore, secret: process.env.ADMIN_PASSWORD, resave: true, saveUninitialized: true, cookie: { maxAge: 7 * 24 * 60 * 60 * 1000 } -})); +} ) ); -app.use(sassMiddleware({ +app.use( sassMiddleware( { // src: __dirname, src: __dirname + '/src/styles', - dest: path.join(__dirname, 'public'), + dest: path.join( __dirname, 'public' ), force: true, // debug: true, outputStyle: 'compressed', response: true -})); +} ) ); -app.use('/js/scripts.js', babelify('src/scripts/scripts.js', { +app.use( '/js/scripts.js', babelify( 'src/scripts/scripts.js', { minify: true -})); +} ) ); -app.engine('handlebars', exphbs({ +app.use('/node_modules', express.static(__dirname + '/node_modules/')); + +app.engine( 'handlebars', exphbs( { defaultLayout: 'main', helpers: { - for: require('./handlebars-helpers/for'), - equals: require('./handlebars-helpers/equals') + for: require( './handlebars-helpers/for' ), + equals: require( './handlebars-helpers/equals' ) } -})); - -app.set('views', __dirname + '/views'); -app.set('view engine', 'handlebars'); +} ) ); -app.use('/', require('./routes/index.js')) -app.use('/admin', require('./routes/admin.js')); -app.use('/bot', require('./routes/bot.js')); -app.use('/delete-post', require('./routes/delete-post.js')); -app.use('/feed', require('./routes/feed.js')); -app.use('/img', express.static(__dirname + '/.data/img/')); +app.set( 'views', __dirname + '/views' ); +app.set( 'view engine', 'handlebars' ); -app.use('/inbox', require('./routes/inbox.js')); -app.use('/outbox', require('./routes/outbox.js')); -app.use('/post', require('./routes/post.js')); -app.use('/pubsub', require('./routes/pubsub.js')); -app.use('/salmon', require('./routes/salmon.js')); -app.use('/webhook', require('./routes/webhook.js')); -app.use('/.well-known', require('./routes/well-known.js')); +app.use( '/', require( './routes/index.js' ) ) +app.use( '/admin', require( './routes/admin.js' ) ); +app.use( '/bot', require( './routes/bot.js' ) ); +app.use( '/delete-post', require( './routes/delete-post.js' ) ); +app.use( '/feed', require( './routes/feed.js' ) ); +app.use( '/img', express.static( __dirname + '/.data/img/' ) ); -app.use(`/${process.env.BOT_ENDPOINT}`, require('./routes/bot-endpoint.js')); +app.use( '/inbox', require( './routes/inbox.js' ) ); +app.use( '/outbox', require( './routes/outbox.js' ) ); +app.use( '/post', require( './routes/post.js' ) ); +app.use( '/pubsub', require( './routes/pubsub.js' ) ); +app.use( '/salmon', require( './routes/salmon.js' ) ); +app.use( '/webhook', require( './routes/webhook.js' ) ); +app.use( '/.well-known', require( './routes/well-known.js' ) ); -app.get('/js/helpers.js', function (req, res) { - res.sendFile(path.join(__dirname + '/helpers/general.js')); -}); +app.get( '/js/helpers.js', function ( req, res ) { + res.sendFile( path.join( __dirname + '/helpers/general.js' ) ); +} ); module.exports = app; diff --git a/bot/bot.js b/bot/bot.js index 1e4be87..4d70ec2 100644 --- a/bot/bot.js +++ b/bot/bot.js @@ -1,54 +1,54 @@ -var fs = require('fs'), - crypto = require('crypto'), - url = require('url'), - util = require('util'), - moment = require('moment'), - dbHelper = require(__dirname + '/../helpers/db.js'), - keys = require(__dirname + '/../helpers/keys.js'), - request = require('request'), - public_key_path = '.data/rsa/pubKey', - private_key_path = '.data/rsa/privKey', - bot_url = `https://${process.env.PROJECT_DOMAIN}.glitch.me`, - botComposeReply = require(__dirname + '/responses.js'); +const fs = require( 'fs' ), + crypto = require( 'crypto' ), + url = require( 'url' ), + util = require( 'util' ), + moment = require( 'moment' ), + dbHelper = require( __dirname + '/../helpers/db.js' ), + keys = require( __dirname + '/../helpers/keys.js' ), + request = require( 'request' ), + publicKeyPath = '.data/rsa/pubKey', + privateKeyPath = '.data/rsa/privKey', + botURL = `https://${ process.env.PROJECT_DOMAIN }.glitch.me`, + botComposeReply = require( __dirname + '/responses.js' ); -if (!fs.existsSync(public_key_path) || !fs.existsSync(private_key_path)) { - keys.generate_keys(function(){ - process.kill(process.pid); - }); +if ( !fs.existsSync( publicKeyPath ) || !fs.existsSync( privateKeyPath ) ) { + keys.generateKeys( function( ){ + process.kill( process.pid ); + } ); } else{ - var public_key = fs.readFileSync(public_key_path, 'utf8'), - private_key = fs.readFileSync(private_key_path, 'utf8'); + let publicKey = fs.readFileSync( publicKeyPath, 'utf8' ), + privateKey = fs.readFileSync( privateKeyPath, 'utf8' ); module.exports = { - bot_url: bot_url, + bot_url: botURL, links: [ // { // rel: 'http://webfinger.net/rel/profile-page', // type: 'text/html', - // href: `${bot_url}` + // href: `${ botURL }` // }, // { // rel: 'http://schemas.google.com/g/2010#updates-from', // type: 'application/atom+xml', - // href: `${bot_url}/feed` + // href: `${ botURL }/feed` // }, { rel: 'self', type: 'application/activity+json', - href: `${bot_url}/bot` + href: `${ botURL }/bot` }, // { // rel: 'hub', - // href: `${bot_url}/pubsub` + // href: `${ botURL }/pubsub` // }, // { // rel: 'salmon', - // href: `${bot_url}/salmon` + // href: `${ botURL }/salmon` // }, // { // rel: 'magic-public-key', - // href: `data:application/magic-public-key,RSA.${public_key.replace('-----BEGIN PUBLIC KEY-----\n', '').replace('\n-----END PUBLIC KEY-----', '').replace('\\n', '')}` + // href: `data:application/magic-public-key,RSA.${ publicKey.replace( '-----BEGIN PUBLIC KEY-----\n', '' ).replace( '\n-----END PUBLIC KEY-----', '' ).replace( '\\n', '' ) }` // } ], info: { @@ -56,7 +56,7 @@ else{ 'https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1' ], - 'id': `${bot_url}/bot`, + 'id': `${ botURL }/bot`, 'icon': [{ 'url': process.env.BOT_AVATAR_URL, 'type': 'Image' @@ -68,223 +68,225 @@ else{ 'type': 'Person', 'name': process.env.BOT_USERNAME, 'preferredUsername': process.env.BOT_USERNAME, - 'inbox': `${bot_url}/inbox`, + 'inbox': `${ botURL }/inbox`, 'publicKey': { - 'id': `${bot_url}/bot#main-key`, - 'owner': `${bot_url}/bot`, - 'publicKeyPem': public_key + 'id': `${ botURL }/bot#main-key`, + 'owner': `${ botURL }/bot`, + 'publicKeyPem': publicKey } }, + // script: botScript, + script: require( __dirname + '/script.js' ), composeReply: botComposeReply, - sendReply: function(options, cb){ - var bot = this, - reply_to_username = ''; + sendReply: function( options, cb ){ + let bot = this, + replyToUsername = ''; try{ - var actor_url_parts = options.payload.actor.split('/'); - var username = actor_url_parts[actor_url_parts.length-1]; - reply_to_username = `@${username}@${url.parse(options.payload.actor).hostname} `; + let actor_url_parts = options.payload.actor.split( '/' ); + let username = actor_url_parts[actor_url_parts.length-1]; + replyToUsername = `@${ username }@${ url.parse( options.payload.actor ).hostname } `; - console.log({reply_to_username}); - } catch(err){ /*noop*/ } + console.log( {replyToUsername} ); + } catch( err ){ /*noop*/ } - bot.createPost({ + bot.createPost( { type: 'Note', - content: `
${options.payload.object.content}${options.payload.object.url}

${options.reply_message}

`, - reply_message: `${reply_to_username} ${options.reply_message}`, + content: `
${ options.payload.object.content }${ options.payload.object.url }

${ options.reply_message }

`, + reply_message: `${ replyToUsername } ${ options.reply_message}`, in_reply_to: options.payload.object.url - }, function(err, message){ - // console.log(err, message); - }); + }, function( err, message ){ + // console.log( err, message ); + } ); }, - createPost: function(options, cb){ - var bot = this; + createPost: function( options, cb ){ + let bot = this; - if ((!options.content || options.content.trim().length === 0 ) && !options.attachment ){ - console.log('error: no post content or attachments'); + if ( ( !options.content || options.content.trim( ).length === 0 ) && !options.attachment ){ + console.log( 'error: no post content or attachments' ); return false; } - var post_type = options.type || 'Note', + let post_type = options.type || 'Note', post_description = options.description, - post_date = moment().format(), + post_date = moment( ).format( ), post_in_reply_to = options.in_reply_to || null, reply_message = options.reply_message || null, post_content = options.content || options.url || '', - post_attachment = JSON.stringify(options.attachment) || '[]'; + post_attachment = JSON.stringify( options.attachment ) || '[]'; - dbHelper.savePost({ + dbHelper.savePost( { type: post_type, content: post_content, attachment: post_attachment - }, function(err, data){ - var post_id = data.lastID; + }, function( err, data ){ + let post_id = data.lastID; - var post_object; + let post_object; - if ( post_type === 'Note' ){ + if ( post_type === 'Note' ){ post_object = { - 'id': `${bot_url}/post/${post_id}`, + 'id': `${ botURL }/post/${ post_id }`, 'type': post_type, 'published': post_date, - 'attributedTo': `${bot_url}/bot`, + 'attributedTo': `${ botURL }/bot`, 'content': reply_message || post_content, 'to': 'https://www.w3.org/ns/activitystreams#Public' }; - if (options.attachment){ - var attachments = []; + if ( options.attachment ){ + let attachments = []; - options.attachment.forEach(function(attachment){ - attachments.push({ + options.attachment.forEach( function( attachment ){ + attachments.push( { 'type': 'Image', 'content': attachment.content, 'url': attachment.url - }); - }); + } ); + } ); post_object.attachment = attachments; } } - if (post_in_reply_to){ + if ( post_in_reply_to ){ post_object.inReplyTo = post_in_reply_to; } - var post = { + let post = { '@context': 'https://www.w3.org/ns/activitystreams', - 'id': `${bot_url}/post/${post_id}`, + 'id': `${ botURL }/post/${ post_id }`, 'type': 'Create', - 'actor': `${bot_url}/bot`, + 'actor': `${ botURL }/bot`, 'object': post_object } - console.log({post_in_reply_to}); + console.log( {post_in_reply_to} ); - dbHelper.getFollowers(function(err, followers){ - if (followers){ - console.log(`sending update to ${followers.length} follower(s)...`); + dbHelper.getFollowers( function( err, followers ){ + if ( followers ){ + console.log( `sending update to ${ followers.length } follower( s )...` ); - followers.forEach(function(follower){ - if (follower.url){ - bot.signAndSend({ + followers.forEach( function( follower ){ + if ( follower.url ){ + bot.signAndSend( { follower: follower, message: post - }, function(err, data){ + }, function( err, data ){ - }); + } ); } - }); + } ); } - }); + } ); - if (cb){ - cb(null, post); + if ( cb ){ + cb( null, post ); } - }); + } ); }, - deletePost: function(post_id, follower_url, cb){ - var bot = this; - // guid = crypto.randomBytes(16).toString('hex'); + deletePost: function( post_id, follower_url, cb ){ + let bot = this; + // guid = crypto.randomBytes( 16 ).toString( 'hex' ); - bot.signAndSend({ + bot.signAndSend( { follower: { url: follower_url }, message: { '@context': 'https://www.w3.org/ns/activitystreams', - // 'summary': `${bot} deleted a post`, - // 'id': `${bot.bot_url}/${guid}`, + // 'summary': `${ bot} deleted a post`, + // 'id': `${ bot.bot_url}/${ guid}`, 'type': 'Delete', - 'actor': `${bot.bot_url}/bot`, - 'object': `${bot.bot_url}/post/${post_id}` + 'actor': `${ bot.bot_url }/bot`, + 'object': `${ bot.bot_url }/post/${ post_id }` } - }, function(err, data){ - if (cb){ - cb(err, data); + }, function( err, data ){ + if ( cb ){ + cb( err, data ); } - }); + } ); }, - accept: function(payload, cb){ - var bot = this, - guid = crypto.randomBytes(16).toString('hex'); + accept: function( payload, cb ){ + let bot = this, + guid = crypto.randomBytes( 16 ).toString( 'hex' ); - dbHelper.getEvent(payload.id, function(err, data){ - // console.log('get_event', err, data); + dbHelper.getEvent( payload.id, function( err, data ){ + // console.log( 'get_event', err, data ); - bot.signAndSend({ + bot.signAndSend( { follower: { url: payload.actor }, message: { '@context': 'https://www.w3.org/ns/activitystreams', - 'id': `${bot.bot_url}/${guid}`, + 'id': `${ bot.bot_url }/${ guid }`, 'type': 'Accept', - 'actor': `${bot.bot_url}/bot`, + 'actor': `${ bot.bot_url }/bot`, 'object': payload, } - }, function(err, data){ - if (cb){ - cb(err, payload, data); + }, function( err, data ){ + if ( cb ){ + cb( err, payload, data ); } - console.log('saving event', payload.id) - dbHelper.saveEvent(payload.id); - }); + console.log( 'saving event', payload.id ) + dbHelper.saveEvent( payload.id ); + } ); - }); -// dbHelper.getEvent(payload.id, function(err, data){ -// console.log('get_event', err, data); + } ); +// dbHelper.getEvent( payload.id, function( err, data ){ +// console.log( 'get_event', err, data ); -// if (!err && !data){ -// bot.signAndSend({ +// if ( !err && !data ){ +// bot.signAndSend( { // follower: { // url: payload.actor // }, // message: { // '@context': 'https://www.w3.org/ns/activitystreams', -// 'id': `${bot.bot_url}/${guid}`, +// 'id': `${ bot.bot_url }/${ guid }`, // 'type': 'Accept', -// 'actor': `${bot.bot_url}/bot`, +// 'actor': `${ bot.bot_url }/bot`, // 'object': payload, // } -// }, function(err, data){ -// if (cb){ -// cb(err, payload, data); +// }, function( err, data ){ +// if ( cb ){ +// cb( err, payload, data ); // } -// console.log('saving event', payload.id) -// dbHelper.saveEvent(payload.id); -// }); -// } else if (!err){ -// console.log('duplicate event'); +// console.log( 'saving event', payload.id ) +// dbHelper.saveEvent( payload.id ); +// } ); +// } else if ( !err ){ +// console.log( 'duplicate event' ); // } -// }); +// } ); }, - signAndSend: function(options, cb){ - var bot = this; - // console.log('message to sign:'); - // console.log(util.inspect(options.message, false, null, true)); + signAndSend: function( options, cb ){ + let bot = this; + // console.log( 'message to sign:' ); + // console.log( util.inspect( options.message, false, null, true ) ); - options.follower.url = options.follower.url.replace('http://localhost:3000', 'https://befc66af.ngrok.io'); + options.follower.url = options.follower.url.replace( 'http://localhost:3000', 'https://befc66af.ngrok.io' ); - if (options.follower.url && options.follower.url !== 'undefined'){ - options.follower.domain = url.parse(options.follower.url).hostname; + if ( options.follower.url && options.follower.url !== 'undefined' ){ + options.follower.domain = url.parse( options.follower.url ).hostname; - var signer = crypto.createSign('sha256'), - d = new Date(), - string_to_sign = `(request-target): post /inbox\nhost: ${options.follower.domain}\ndate: ${d.toUTCString()}`; + let signer = crypto.createSign( 'sha256' ), + d = new Date( ), + string_to_sign = `( request-target ): post /inbox\nhost: ${ options.follower.domain}\ndate: ${ d.toUTCString() }`; - signer.update(string_to_sign); - signer.end(); + signer.update( string_to_sign ); + signer.end( ); - var signature = signer.sign(private_key); - var signature_b64 = signature.toString('base64'); - var header = `keyId="${bot_url}/bot",headers="(request-target) host date",signature="${signature_b64}"`; + let signature = signer.sign( privateKey ); + let signatureB64 = signature.toString( 'base64' ); + let header = `keyId="${ botURL }/bot",headers="( request-target ) host date",signature="${ signatureB64 }"`; - var req_object = { - url: `https://${options.follower.domain}/inbox`, + let reqObject = { + url: `https://${ options.follower.domain }/inbox`, headers: { 'Host': options.follower.domain, - 'Date': d.toUTCString(), + 'Date': d.toUTCString( ), 'Signature': header }, method: 'POST', @@ -292,23 +294,23 @@ else{ body: options.message }; - // console.log('request object:'); - // console.log(util.inspect(req_object, false, null, true)); + console.log( 'request object:' ); + console.log( util.inspect( reqObject, false, null, true ) ); - request(req_object, function (error, response){ - console.log(`sent message to ${options.follower.url}...`); - if (error) { - console.log('error:', error, response); + request( reqObject, function ( error, response ){ + console.log( `sent message to ${ options.follower.url }...` ); + if ( error ) { + console.log( 'error:', error, response ); } else { - console.log('response:', response.statusCode, response.statusMessage); - // console.log(response); + console.log( 'response:', response.statusCode, response.statusMessage ); + console.log( response.body ); } - if (cb){ - cb(error, response); + if ( cb ){ + cb( error, response ); } - }); + } ); } } }; diff --git a/bot/script.js b/bot/script.js new file mode 100644 index 0000000..83dd5c0 --- /dev/null +++ b/bot/script.js @@ -0,0 +1,19 @@ +const express = require( 'express' ), + router = express.Router(), + grammar = require( __dirname + '/../tracery/tracery.js' ).grammar; + +module.exports = function(){ + const bot = require( __dirname + '/bot.js' ), + content = grammar.flatten( '#origin#' ); + + console.log( 'posting new message...' ); + + bot.createPost( { + type: 'Note', // See www.w3.org/ns/activitystreams#objects + content: content + }, function( err, message ){ + + + } ); + +}; diff --git a/helpers/cron-schedules.js b/helpers/cron-schedules.js new file mode 100644 index 0000000..55b88a4 --- /dev/null +++ b/helpers/cron-schedules.js @@ -0,0 +1,20 @@ +module.exports = { + EVERY_FIVE_SECONDS: '*/5 * * * * *', + EVERY_TEN_SECONDS: '*/10 * * * * *', + EVERY_THIRTY_SECONDS: '*/30 * * * * *', + EVERY_MINUTE: '* * * * *', + EVERY_FIVE_MINUTES: '*/5 * * * *', + EVERY_TEN_MINUTES: '*/10 * * * *', + EVERY_THIRTY_MINUTES: '*/30 * * * *', + EVERY_HOUR: '0 * * * *', + EVERY_TWO_HOURS: '0 */2 * * *', + EVERY_THREE_HOURS: '0 */3 * * *', + EVERY_FOUR_HOURS: '0 */4 * * *', + EVERY_SIX_HOURS: '0 */6 * * *', + EVERY_TWELVE_HOURS: '0 */12 * * *', + EVERY_DAY_MIDNIGHT: '0 0 * * *', + EVERY_DAY_MORNING: '0 8 * * *', + EVERY_DAY_NOON: '0 12 * * *', + EVERY_DAY_AFTERNOON: '0 14 * * *', + EVERY_DAY_EVENING: '0 19 * * *' +}; \ No newline at end of file diff --git a/helpers/general.js b/helpers/general.js index 310d7fa..28f85ca 100644 --- a/helpers/general.js +++ b/helpers/general.js @@ -1,94 +1,94 @@ -if (typeof module !== 'undefined'){ - var fs = require('fs'), - path = require('path'), - request = require('request'); +if ( typeof module !== 'undefined' ){ + const fs = require( 'fs' ), + path = require( 'path' ), + request = require( 'request' ); } -var helpers = { +const helpers = { getTimestamp: function(){ - return Math.round((new Date()).getTime() / 1000); + return Math.round( ( new Date() ).getTime() / 1000 ); }, - randomFromArray: function(arr) { - return arr[Math.floor(Math.random()*arr.length)]; + randomFromArray: function( arr ){ + return arr[Math.floor( Math.random()*arr.length )]; }, - getRandomInt: function(min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min; + getRandomInt: function( min, max ){ + return Math.floor( Math.random() * ( max - min + 1 ) ) + min; }, - getRandomRange: function(min, max, fixed) { - return (Math.random() * (max - min) + min).toFixed(fixed) * 1; + getRandomRange: function( min, max, fixed ){ + return ( Math.random() * ( max - min ) + min ).toFixed( fixed ) * 1; }, - getRandomHex: function() { - return '#' + Math.random().toString(16).slice(2, 8).toUpperCase(); + getRandomHex: function(){ + return '#' + Math.random().toString( 16 ).slice( 2, 8 ).toUpperCase(); }, - shadeColor: function(color, percent) { + shadeColor: function( color, percent ){ // https://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors - var f = parseInt(color.slice(1),16),t=percent<0?0:255,p=percent<0?percent*-1:percent,R=f>>16,G=f>>8&0x00FF,B=f&0x0000FF; - return `#${(0x1000000+(Math.round((t-R)*p)+R)*0x10000+(Math.round((t-G)*p)+G)*0x100+(Math.round((t-B)*p)+B)).toString(16).slice(1)}`; + let f = parseInt( color.slice( 1 ),16 ),t=percent<0?0:255,p=percent<0?percent*-1:percent,R=f>>16,G=f>>8&0x00FF,B=f&0x0000FF; + return `#${( 0x1000000+( Math.round( ( t-R )*p )+R )*0x10000+( Math.round( ( t-G )*p )+G )*0x100+( Math.round( ( t-B )*p )+B ) ).toString( 16 ).slice( 1 )}`; }, - loadImageAssets: function(cb){ + loadImageAssets: function( cb ){ /* Load images from the assets folder */ - console.log('reading assets folder...') - var that = this; - fs.readFile('./.glitch-assets', 'utf8', function (err, data) { - if (err) { - console.log('error:', err); + console.log( 'reading assets folder...' ) + let that = this; + fs.readFile( './.glitch-assets', 'utf8', function ( err, data ){ + if ( err ){ + console.log( 'error:', err ); return false; } - data = data.split('\n'); - var data_json = JSON.parse('[' + data.join(',').slice(0, -1) + ']'), - deleted_images = data_json.reduce(function(filtered, data_img) { - if (data_img.deleted) { - var someNewValue = { name: data_img.name, newProperty: 'Foo' } - filtered.push(data_img.uuid); + data = data.split( '\n' ); + let data_json = JSON.parse( '[' + data.join( ',' ).slice( 0, -1 ) + ']' ), + deleted_images = data_json.reduce( function( filtered, data_img ){ + if ( data_img.deleted ){ + let someNewValue = { name: data_img.name, newProperty: 'Foo' } + filtered.push( data_img.uuid ); } return filtered; - }, []), + }, [] ), img_urls = []; - for (var i = 0, j = data.length; i < j; i++){ - if (data[i].length){ - var img_data = JSON.parse(data[i]), + for ( let i = 0, j = data.length; i < j; i++ ){ + if ( data[i].length ){ + let img_data = JSON.parse( data[i] ), image_url = img_data.url; - if (image_url && deleted_images.indexOf(img_data.uuid) === -1 && that.extension_check(image_url)){ - var file_name = that.get_filename_from_url(image_url).split('%2F')[1]; - // console.log(`- ${file_name}`); - img_urls.push(image_url); + if ( image_url && deleted_images.indexOf( img_data.uuid ) === -1 && that.extension_check( image_url ) ){ + let file_name = that.get_filename_from_url( image_url ).split( '%2F' )[1]; + // console.log( `- ${file_name}` ); + img_urls.push( image_url ); } } } - cb(null, img_urls); - }); + cb( null, img_urls ); + } ); }, - extensionCheck: function(url) { - var file_extension = path.extname(url).toLowerCase(), + extensionCheck: function( url ){ + let file_extension = path.extname( url ).toLowerCase(), extensions = ['.png', '.jpg', '.jpeg', '.gif']; - return extensions.indexOf(file_extension) !== -1; + return extensions.indexOf( file_extension ) !== -1; }, - getFilenameFromUrl: function(url) { - return url.substring(url.lastIndexOf('/') + 1); + getFilenameFromUrl: function( url ){ + return url.substring( url.lastIndexOf( '/' ) + 1 ); }, - loadImage: function(url, cb) { - console.log(`loading remote image: ${url} ...`); - request({url: url, encoding: null}, function (err, res, body) { - if (!err && res.statusCode == 200) { - var b64content = 'data:' + res.headers['content-type'] + ';base64,'; - console.log('image loaded...'); - cb(null, body.toString('base64')); + loadImage: function( url, cb ){ + console.log( `loading remote image: ${url} ...` ); + request( {url: url, encoding: null}, function ( err, res, body ){ + if ( !err && res.statusCode == 200 ){ + let b64content = 'data:' + res.headers['content-type'] + ';base64,'; + console.log( 'image loaded...' ); + cb( null, body.toString( 'base64' ) ); } else { - console.log('ERROR:', err); - cb(err); + console.log( 'ERROR:', err ); + cb( err ); } - }); + } ); }, - downloadFile: function(uri, filename, cb){ - request.head(uri, function(err, res, body){ - request(uri).pipe(fs.createWriteStream(filename)).on('close', cb); - }); + downloadFile: function( uri, filename, cb ){ + request.head( uri, function( err, res, body ){ + request( uri ).pipe( fs.createWriteStream( filename ) ).on( 'close', cb ); + } ); } }; -if (typeof module !== 'undefined'){ +if ( typeof module !== 'undefined' ){ /* This is to make the file usable both in node and on the front end. */ module.exports = helpers; } diff --git a/helpers/image-uploader.js b/helpers/image-uploader.js index d187e45..1381830 100644 --- a/helpers/image-uploader.js +++ b/helpers/image-uploader.js @@ -1,59 +1,58 @@ -var fs = require('fs'), - bot = require(__dirname + '/../bot/bot.js'), - NeoCities = require('neocities'), - use_neocities = false; +const fs = require( 'fs' ), + bot = require( __dirname + '/../bot/bot.js' ), + NeoCities = require( 'neocities' ); +let useNeocities = false; -if (process.env.NEOCITIES_USERNAME && process.env.NEOCITIES_PASSWORD){ - var neocities_api = new NeoCities(process.env.NEOCITIES_USERNAME, process.env.NEOCITIES_PASSWORD); - use_neocities = true; +if ( process.env.NEOCITIES_USERNAME && process.env.NEOCITIES_PASSWORD ){ + const neocitiesAPI = new NeoCities( process.env.NEOCITIES_USERNAME, process.env.NEOCITIES_PASSWORD ); + useNeocities = true; } module.exports = { - uploadImage: function(img_data, cb){ - var img_url = `${bot.bot_url}/${img_data.path}`, - img_name = img_data.path.replace('img/', ''); + uploadImage: function( img_data, cb ){ + let img_url = `${bot.bot_url}/${img_data.path}`, + img_name = img_data.path.replace( 'img/', '' ); - if (use_neocities){ + if ( useNeocities ){ /* First option, NeoCities. They offer 1GB for free, and with a - paid option ($5/month) you get 50GB. + paid option ( $5/month ) you get 50GB. https://neocities.org/supporter */ - neocities_api.upload([ - { + neocitiesAPI.upload( [ { name: img_name, path: `.data/img/${img_name}` - } - ], function(resp) { - console.log(resp); - var img_url = null; + } ], function( resp ) { + console.log( resp ); + img_url = null; - if (resp && resp.result === 'success'){ - fs.unlink(`.data/img/${img_name}`, function(err){ - if (err){ - console.log(err); + if ( resp && resp.result === 'success' ){ + fs.unlink( `.data/img/${img_name}`, function( err ){ + if ( err ){ + console.log( err ); } else{ - console.log('deleted local image'); + console.log( 'deleted local image' ); } - }); + } ); img_url = `https://${process.env.NEOCITIES_USERNAME}.neocities.org/${img_name}`; } - if (cb){ - cb(null, img_url, resp); + if ( cb ){ + cb( null, img_url, resp ); } - }); + } ); } else { /* Fall-back to local storage. It's only ~128 MB, so good luck! */ - if (cb){ - cb(null, img_url); + if ( cb ){ + cb( null, img_url ); } } } }; + diff --git a/helpers/keys.js b/helpers/keys.js index b01d97f..6c32054 100644 --- a/helpers/keys.js +++ b/helpers/keys.js @@ -1,25 +1,25 @@ -var fs = require('fs'), - util = require('util'), - generate_rsa_keypair = require('generate-rsa-keypair'), - pem = require('pem'), - pubkey_path = '.data/rsa/pubKey', - privkey_path = '.data/rsa/privKey'; +const fs = require( 'fs' ), + util = require( 'util' ), + generate_rsa_keypair = require( 'generate-rsa-keypair' ), + pem = require( 'pem' ), + pubkey_path = '.data/rsa/pubKey', + privkey_path = '.data/rsa/privKey'; module.exports = { - generateKeys: function(cb) { - console.log('generating keys...'); + generateKeys: function( cb ) { + console.log( 'generating keys...' ); try{ - fs.mkdirSync('.data/rsa'); - } catch(err){ /* noop */ } + fs.mkdirSync( '.data/rsa' ); + } catch( err ){ /* noop */ } - var pair = generate_rsa_keypair(); + var pair = generate_rsa_keypair( ); - fs.writeFileSync(privkey_path, pair.private); - fs.writeFileSync(pubkey_path, pair.public); + fs.writeFileSync( privkey_path, pair.private ); + fs.writeFileSync( pubkey_path, pair.public ); - if (cb){ - cb(null); + if ( cb ){ + cb( null ); } } }; diff --git a/package.json b/package.json index a11f38d..6599b6b 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "start": "node server.js" }, "dependencies": { + "cron": "^1.8.2", "express": "^4.16.3", "sqlite3": "^4.0.0", "express-handlebars": "^3.0.0", diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..d65f680 --- /dev/null +++ b/robots.txt @@ -0,0 +1,3 @@ +User-agent: MastoPeek v0.7.2 - https://mastopeek.app-dist.eu +User-agent: fediverse.space crawler +Disallow: / diff --git a/routes/admin.js b/routes/admin.js index da923b7..49d87cb 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -1,47 +1,47 @@ -var express = require('express'), - session = require('express-session'), - router = express.Router(), - moment = require('moment'), - db = require(__dirname + '/../helpers/db.js'), - bot = require(__dirname + '/../bot/bot.js'); +const express = require( 'express' ), + session = require( 'express-session' ), + router = express.Router(), + moment = require( 'moment' ), + db = require( __dirname + '/../helpers/db.js' ), + bot = require( __dirname + '/../bot/bot.js' ); -router.get('/', function (req, res) { - res.render('../views/admin.handlebars', { +router.get( '/', function ( req, res ) { + res.render( '../views/admin.handlebars', { project_name: process.env.PROJECT_DOMAIN, bot_avatar_url: process.env.BOT_AVATAR_URL, bot_username: process.env.BOT_USERNAME, bot_description: process.env.BOT_DESCRIPTION - }); -}); + } ); +} ); -router.get('/logout', function (req, res) { +router.get( '/logout', function ( req, res ) { req.session.is_admin = false; req.session.save(); - console.log('admin logged out'); - console.log(req.body); - res.redirect('/'); -}); + console.log( 'admin logged out' ); + console.log( req.body ); + res.redirect( '/' ); +} ); -router.post('/', function (req, res) { - if (process.env.ADMIN_PASSWORD && req.body.password){ - if (req.body.password === process.env.ADMIN_PASSWORD){ +router.post( '/', function ( req, res ) { + if ( process.env.ADMIN_PASSWORD && req.body.password ){ + if ( req.body.password === process.env.ADMIN_PASSWORD ){ req.session.is_admin = true; req.session.save(); - console.log('saving session...', req.session.is_admin); + console.log( 'saving session...', req.session.is_admin ); - req.session.save(function(err) { - console.log('admin logged in'); - res.redirect('/'); - }); + req.session.save( function( err ) { + console.log( 'admin logged in' ); + res.redirect( '/' ); + } ); } else{ req.session.is_admin = false; - console.log('failed login attempt'); - console.log(req.body); - res.redirect('/admin'); + console.log( 'failed login attempt' ); + console.log( req.body ); + res.redirect( '/admin' ); } } -}); +} ); module.exports = router; diff --git a/routes/bot-endpoint.js b/routes/bot-endpoint.js deleted file mode 100644 index 40a06bf..0000000 --- a/routes/bot-endpoint.js +++ /dev/null @@ -1,18 +0,0 @@ -var express = require('express'), - router = express.Router(), - grammar = require(__dirname + '/../tracery/tracery.js').grammar, - bot = require(__dirname + '/../bot/bot.js'); - -router.get('/', function (req, res) { - var content = grammar.flatten("#origin#"); - - bot.createPost({ - type: 'Note', // See www.w3.org/ns/activitystreams#objects - content: content - }, function(err, message){ - res.setHeader('Content-Type', 'application/json'); - res.send(JSON.stringify(message)); - }); -}); - -module.exports = router; diff --git a/routes/bot.js b/routes/bot.js index 09c0a35..e35f851 100644 --- a/routes/bot.js +++ b/routes/bot.js @@ -1,24 +1,22 @@ -var fs = require('fs'), - url = require('url'), - util = require('util'), - bot = require(__dirname + '/../bot/bot.js'); +const fs = require( 'fs' ), + url = require( 'url' ), + util = require( 'util' ), + bot = require( __dirname + '/../bot/bot.js' ), + express = require( 'express' ), + router = express.Router( ); - -var express = require('express'), - router = express.Router(); - -router.get('/', function (req, res) { - var url_parts = url.parse(req.url, true); +router.get( '/', function( req, res ) { + const urlParts = url.parse( req.url, true ); - if (req.headers['user-agent'].indexOf('mastodon') !== -1 || (req.query.debug && req.query.debug !== '')){ - res.setHeader('Content-Type', 'application/json'); - // console.log(bot.info); - // res.send(JSON.stringify(bot.info)); - res.json(bot.info); + if ( req.headers['user-agent'].indexOf( 'mastodon' ) !== -1 || ( req.query.debug && req.query.debug !== '' ) ){ + res.setHeader( 'Content-Type', 'application/json' ); + // console.log( bot.info ); + // res.send( JSON.stringify( bot.info ) ); + res.json( bot.info ); } else{ - res.redirect('/'); + res.redirect( '/' ); } -}); +} ); module.exports = router; diff --git a/routes/delete-post.js b/routes/delete-post.js index e5f944d..c42845e 100644 --- a/routes/delete-post.js +++ b/routes/delete-post.js @@ -1,15 +1,15 @@ -var express = require( 'express' ), - router = express.Router(), - moment = require( 'moment' ), - bot = require( __dirname + '/../bot/bot.js' ), - db = require( __dirname + '/../helpers/db.js' ); +const express = require( 'express' ), + router = express.Router(), + moment = require( 'moment' ), + bot = require( __dirname + '/../bot/bot.js' ), + db = require( __dirname + '/../helpers/db.js' ); router.get( '/:id', function( req, res ) { - var is_admin = req.session.is_admin, - post_id = req.params.id; + let isAdmin = req.session.is_admin, + postID = req.params.id; - if ( is_admin ){ - if ( post_id === 'all' ){ + if ( isAdmin ){ + if ( postID === 'all' ){ console.log( { 'delete post': 'all of them' } ); @@ -38,14 +38,14 @@ router.get( '/:id', function( req, res ) { } else { console.log( { - 'delete post': post_id + 'delete post': postID } ); - db.deletePost( post_id, bot, function( err ){ + db.deletePost( postID, bot, function( err ){ if ( err ){ - console.log( `error deleting post ${post_id}`, err ); + console.log( `error deleting post ${postID}`, err ); } else { - console.log( `deleted post ${post_id}` ); + console.log( `deleted post ${postID}` ); } } ); res.redirect( '/' ); diff --git a/routes/feed.js b/routes/feed.js index dfdd568..ac50aff 100644 --- a/routes/feed.js +++ b/routes/feed.js @@ -1,9 +1,8 @@ -var express = require( 'express' ), - router = express.Router(), - RSS = require( 'rss' ), - moment = require( 'moment' ), - dbHelper = require( __dirname + '/../helpers/db.js' ); - +const express = require( 'express' ), + router = express.Router(), + RSS = require( 'rss' ), + moment = require( 'moment' ), + dbHelper = require( __dirname + '/../helpers/db.js' ); router.get( '/', function( req, res ) { let xml = ''; diff --git a/routes/inbox.js b/routes/inbox.js index 8cc8d1a..ec466bf 100644 --- a/routes/inbox.js +++ b/routes/inbox.js @@ -1,89 +1,87 @@ -var fs = require('fs'), - url = require('url'), - crypto = require('crypto'), - util = require('util'), - jsdom = require('jsdom'), - dbHelper = require(__dirname + '/../helpers/db.js'), - bot = require(__dirname + '/../bot/bot.js'); +const fs = require( 'fs' ), + url = require( 'url' ), + crypto = require( 'crypto' ), + util = require( 'util' ), + jsdom = require( 'jsdom' ), + dbHelper = require( __dirname + '/../helpers/db.js' ), + bot = require( __dirname + '/../bot/bot.js' ), + { JSDOM } = jsdom, + express = require( 'express' ), + router = express.Router( ); -const { JSDOM } = jsdom; - -var express = require('express'), - router = express.Router(); - -router.post('/', function (req, res) { - var url_parts = url.parse(req.url, true), +router.post( '/', function ( req, res ) { + let urlParts = url.parse( req.url, true ), payload = req.body; - console.log('/inbox'); + console.log( '/inbox' ); - console.log(payload.id); + console.log( payload.id ); /* TODO: Verify the message. */ - if (payload.type === 'Follow'){ + if ( payload.type === 'Follow' ){ - bot.accept(payload, function(err, payload, data){ - if (!err){ - dbHelper.saveFollower(payload, function(err, data){ - console.log(`new follower ${payload.actor} saved`); - }); + bot.accept( payload, function( err, payload, data ){ + if ( !err ){ + dbHelper.saveFollower( payload, function( err, data ){ + console.log( `new follower ${payload.actor} saved` ); + } ); } - res.status(200); - }); + res.status( 200 ); + } ); } - else if (payload.type === 'Undo'){ - bot.accept(payload, function(err, payload, data){ - if (!err){ - dbHelper.removeFollower(payload, function(err, data){ - console.log(`removed follower ${payload.actor}`); - }); + else if ( payload.type === 'Undo' ){ + bot.accept( payload, function( err, payload, data ){ + if ( !err ){ + dbHelper.removeFollower( payload, function( err, data ){ + console.log( `removed follower ${payload.actor}` ); + } ); } - res.status(200); - }); + res.status( 200 ); + } ); } - else if (payload.type === 'Create'){ - bot.accept(payload, function(err, payload, data){ - if (!err && payload.object && payload.object.content){ - var dom = new JSDOM(`
${payload.object.content}
`), + else if ( payload.type === 'Create' ){ + bot.accept( payload, function( err, payload, data ){ + if ( !err && payload.object && payload.object.content ){ + let dom = new JSDOM( `
${payload.object.content}
` ), message_body = ''; try { message_body = dom.window.document.body.firstChild.textContent; - } catch(err){ /* noop */} + } catch( err ){ /* noop */} - bot.composeReply({ + bot.composeReply( { payload: payload, message_from: payload.actor, message_body: message_body, - }, function(err, reply_message){ - if (!err){ - console.log(err); - console.log('sending reply...'); - bot.sendReply({ + }, function( err, reply_message ){ + if ( !err ){ + console.log( err ); + console.log( 'sending reply...' ); + bot.sendReply( { payload: payload, message_body: message_body, reply_message: reply_message - }, function(err, data){ + }, function( err, data ){ - }); + } ); } - }); + } ); } - res.status(200); - }); + res.status( 200 ); + } ); } - else if (payload.type === 'Delete'){ - // console.log('payload', payload); - console.log('Delete /*noop*/'); - res.status(200); + else if ( payload.type === 'Delete' ){ + // console.log( 'payload', payload ); + console.log( 'Delete /*noop*/' ); + res.status( 200 ); } else{ - console.log('payload', payload); - res.status(200); + console.log( 'payload', payload ); + res.status( 200 ); } -}); +} ); module.exports = router; diff --git a/routes/index.js b/routes/index.js index 3b878d2..31a4c5c 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,52 +1,55 @@ -var express = require('express'), - session = require('express-session'), - router = express.Router(), - moment = require('moment'), - db = require(__dirname + '/../helpers/db.js'), - bot = require(__dirname + '/../bot/bot.js'); +const fs = require( 'fs' ), + express = require( 'express' ), + session = require( 'express-session' ), + router = express.Router( ), + moment = require( 'moment' ), + db = require( __dirname + '/../helpers/db.js' ), + bot = require( __dirname + '/../bot/bot.js' ), + publicKeyPath = '.data/rsa/pubKey'; -router.get('/', function (req, res) { - // console.log(req.headers); - // console.log(JSON.stringify(actor)); + +router.get( '/', function ( req, res ) { + // console.log( req.headers ); + // console.log( JSON.stringify( actor ) ); - if (req.headers && req.headers['user-agent'] && req.headers['user-agent'].indexOf('Mastodon') !== -1 ){ - console.log(req.headers['user-agent']); - res.setHeader('Content-Type', 'application/json'); - res.send(JSON.stringify(bot.info)); + if ( req.headers && req.headers['user-agent'] && req.headers['user-agent'].indexOf( 'Mastodon' ) !== -1 ){ + console.log( req.headers['user-agent'] ); + res.setHeader( 'Content-Type', 'application/json' ); + res.send( JSON.stringify( bot.info ) ); } else{ - var page = parseInt(req.query.page) || 1; + let page = parseInt( req.query.page ) || 1; - db.getPosts({ + db.getPosts( { page: page - }, function(err, data){ - // console.log(posts); + }, function( err, data ){ + // console.log( posts ); - var no_posts = false; + let noPosts = false; - if (data && data.posts && data.posts.length > 0){ - data.posts.forEach(function(post){ - post.date_formatted = moment(post.date).fromNow(); + if ( data && data.posts && data.posts.length > 0 ){ + data.posts.forEach( function( post ){ + post.date_formatted = moment( post.date ).fromNow( ); try{ - post.attachment = JSON.parse(post.attachment); - } catch(err){ /*noop*/ } - }); + post.attachment = JSON.parse( post.attachment ); + } catch( err ){ /*noop*/ } + } ); } else { - no_posts = true; + noPosts = true; } - var show_next_page = false, - show_previous_page = false; + let showNextPage = false, + showPreviousPage = false; - if (page < data.page_count){ - show_next_page = true; + if ( page < data.page_count ){ + showNextPage = true; } - if (page > 1 && page <= data.page_count){ - show_previous_page = true; + if ( page > 1 && page <= data.page_count ){ + showPreviousPage = true; } - res.render('../views/home.handlebars', { + res.render( '../views/home.handlebars', { project_name: process.env.PROJECT_DOMAIN, bot_url: `https://${process.env.PROJECT_DOMAIN}.glitch.me/`, bot_avatar_url: process.env.BOT_AVATAR_URL, @@ -58,23 +61,23 @@ router.get('/', function (req, res) { post_count: data.post_count, page_count: data.page_count, posts: data.posts, - has_posts: !no_posts, - no_posts: no_posts, + has_posts: !noPosts, + no_posts: noPosts, current_page: page, show_pagination: data.page_count > 1, next_page: page + 1, previous_page: page - 1, - show_next_page: show_next_page, - show_previous_page: show_previous_page, + show_next_page: showNextPage, + show_previous_page: showPreviousPage, show_admin_link: process.env.SHOW_ADMIN_LINK && - (process.env.SHOW_ADMIN_LINK === 'true' || process.env.SHOW_ADMIN_LINK === 'yes' ? true : false) - }); - }); + ( process.env.SHOW_ADMIN_LINK === 'true' || process.env.SHOW_ADMIN_LINK === 'yes' ? true : false ) + } ); + } ); } -}); +} ); -router.get('/about', function (req, res) { - res.render('../views/about.handlebars', { +router.get( '/about', function ( req, res ) { + res.render( '../views/about.handlebars', { project_name: process.env.PROJECT_DOMAIN, bot_url: `https://${process.env.PROJECT_DOMAIN}.glitch.me/`, bot_avatar_url: process.env.BOT_AVATAR_URL, @@ -82,7 +85,27 @@ router.get('/about', function (req, res) { bot_description: process.env.BOT_DESCRIPTION, page_title: process.env.BOT_USERNAME, page_description: process.env.BOT_DESCRIPTION + } ); +} ); + +router.get( '/id.pub', function ( req, res ) { + let publicKey = fs.readFileSync( publicKeyPath, 'utf8' ); + + fs.readFile( publicKeyPath, 'utf8' ,function( err, contents ){ + res.writeHead( 200, { 'Content-Type': 'text/plain' } ); + res.write( contents ); + res.end(); }); -}); + +} ); + +router.get( '/robots.txt', function ( req, res ) { + fs.readFile( 'robots.txt', 'utf8' ,function( err, contents ){ + res.writeHead( 200, { 'Content-Type': 'text/plain' } ); + res.write( contents ); + res.end(); + }); + +} ); module.exports = router; diff --git a/routes/outbox.js b/routes/outbox.js index 8078b94..e72855b 100644 --- a/routes/outbox.js +++ b/routes/outbox.js @@ -1,20 +1,19 @@ -var fs = require('fs'), - url = require('url'), - util = require('util'), - bot = require(__dirname + '/../bot/bot.js'); +const fs = require( 'fs' ), + url = require( 'url' ), + util = require( 'util' ), + bot = require( __dirname + '/../bot/bot.js' ), + express = require( 'express' ), + router = express.Router( ); -var express = require('express'), - router = express.Router(); +router.all( '/', function( req, res ) { + const urlParts = url.parse( req.url, true ); -router.all('/', function (req, res) { - var url_parts = url.parse(req.url, true); + console.log( '/outbox', urlParts ); - console.log('/outbox', url_parts); - - res.setHeader('Content-Type', 'application/json'); - res.send(JSON.stringify({ + res.setHeader( 'Content-Type', 'application/json' ); + res.send( JSON.stringify( { error: null - })); -}); + } ) ); +} ); module.exports = router; diff --git a/routes/post.js b/routes/post.js index 01513ce..c251143 100644 --- a/routes/post.js +++ b/routes/post.js @@ -1,20 +1,21 @@ -var express = require('express'), - router = express.Router(), - moment = require('moment'), - db = require(__dirname + '/../helpers/db.js'); +const express = require( 'express' ), + router = express.Router(), + moment = require( 'moment' ), + db = require( __dirname + '/../helpers/db.js' ); -router.get('/:id', function(req, res) { - var post_id = req.params.id; - db.getPost(post_id, function(err, post_data){ - if (post_data){ - post_data.date_formatted = moment(post_data.date).fromNow();; +router.get( '/:id', function( req, res ) { + const postID = req.params.id; + + db.getPost( postID, function( err, post_data ){ + if ( post_data ){ + post_data.date_formatted = moment( post_data.date ).fromNow();; try{ - post_data.attachment = JSON.parse(post_data.attachment); - } catch(err){ /*noop*/ } + post_data.attachment = JSON.parse( post_data.attachment ); + } catch( err ){ /*noop*/ } - res.render('../views/post.handlebars', { + res.render( '../views/post.handlebars', { project_name: process.env.PROJECT_DOMAIN, bot_url: `https://${process.env.PROJECT_DOMAIN}.glitch.me/`, bot_avatar_url: process.env.BOT_AVATAR_URL, @@ -24,10 +25,10 @@ router.get('/:id', function(req, res) { page_title: `${process.env.BOT_USERNAME}: ${post_data.date}`, page_description: post_data.content, post: post_data - }); + } ); } else{ - res.render('../views/404.handlebars', { + res.render( '../views/404.handlebars', { project_name: process.env.PROJECT_DOMAIN, bot_url: `https://${process.env.PROJECT_DOMAIN}.glitch.me/`, bot_avatar_url: process.env.BOT_AVATAR_URL, @@ -35,9 +36,9 @@ router.get('/:id', function(req, res) { bot_description: process.env.BOT_DESCRIPTION, page_title: `${process.env.BOT_USERNAME}: Page not found`, is_admin: req.session.is_admin - }); + } ); } - }); -}); + } ); +} ); module.exports = router; diff --git a/routes/pubsub.js b/routes/pubsub.js index bae74c5..f9a2cd4 100644 --- a/routes/pubsub.js +++ b/routes/pubsub.js @@ -1,20 +1,19 @@ -var fs = require('fs'), - url = require('url'), - util = require('util'), - bot = require(__dirname + '/../bot/bot.js'); +const fs = require( 'fs' ), + url = require( 'url' ), + util = require( 'util' ), + bot = require( __dirname + '/../bot/bot.js' ), + express = require( 'express' ), + router = express.Router( ); -var express = require('express'), - router = express.Router(); +router.all( '/', function( req, res ) { + const urlParts = url.parse( req.url, true ); -router.all('/', function (req, res) { - var url_parts = url.parse(req.url, true); + console.log( '/pubsub', urlParts ); - console.log('/pubsub', url_parts); - - res.setHeader('Content-Type', 'application/json'); - res.send(JSON.stringify({ + res.setHeader( 'Content-Type', 'application/json' ); + res.send( JSON.stringify( { error: null - })); -}); + } ) ); +} ); module.exports = router; diff --git a/routes/salmon.js b/routes/salmon.js index 1db92e9..abc2848 100644 --- a/routes/salmon.js +++ b/routes/salmon.js @@ -1,20 +1,19 @@ -var fs = require('fs'), - url = require('url'), - util = require('util'), - bot = require(__dirname + '/../bot/bot.js'); +const fs = require( 'fs' ), + url = require( 'url' ), + util = require( 'util' ), + bot = require( __dirname + '/../bot/bot.js' ), + express = require( 'express' ), + router = express.Router( ); -var express = require('express'), - router = express.Router(); +router.all( '/', function( req, res ) { + const urlParts = url.parse( req.url, true ); -router.all('/', function (req, res) { - var url_parts = url.parse(req.url, true); + console.log( '/salmon', urlParts ); - console.log('/salmon', url_parts); - - res.setHeader('Content-Type', 'application/json'); - res.send(JSON.stringify({ + res.setHeader( 'Content-Type', 'application/json' ); + res.send( JSON.stringify( { error: null - })); -}); + } ) ); +} ); module.exports = router; diff --git a/routes/webhook.js b/routes/webhook.js index 1937139..5007ed2 100644 --- a/routes/webhook.js +++ b/routes/webhook.js @@ -1,21 +1,20 @@ -var fs = require('fs'), - url = require('url'), - util = require('util'), - bot = require(__dirname + '/../bot/bot.js'); +const fs = require( 'fs' ), + url = require( 'url' ), + util = require( 'util' ), + bot = require( __dirname + '/../bot/bot.js' ), + express = require( 'express' ), + router = express.Router(); -var express = require('express'), - router = express.Router(); +router.get( '/', function( req, res ) { + const urlParts = url.parse( req.url, true ); -router.get('/', function (req, res) { - var url_parts = url.parse(req.url, true); + console.log( '/webhook', urlParts ); - console.log('/webhook', url_parts); - - res.setHeader('Content-Type', 'application/json'); - res.send(JSON.stringify({ + res.setHeader( 'Content-Type', 'application/json' ); + res.send( JSON.stringify( { error: null - })); -}); + } ) ); +} ); module.exports = router; diff --git a/routes/well-known.js b/routes/well-known.js index 848f08e..b49891f 100644 --- a/routes/well-known.js +++ b/routes/well-known.js @@ -1,24 +1,23 @@ -var fs = require('fs'), - url = require('url'), - util = require('util'), - bot = require(__dirname + '/../bot/bot.js'); +const fs = require( 'fs' ), + url = require( 'url' ), + util = require( 'util' ), + bot = require( __dirname + '/../bot/bot.js' ), + express = require( 'express' ), + router = express.Router(); -var express = require('express'), - router = express.Router(); +router.get( '/webfinger', function( req, res ) { + const urlPparts = url.parse( req.url, true ), + query = urlPparts.query; -router.get('/webfinger', function (req, res) { - var url_parts = url.parse(req.url, true), - query = url_parts.query; - - // console.log('webfinger request', query, { + // console.log( 'webfinger request', query, { // subject: query.resource, // links: bot.links - // }); + // } ); - res.json({ + res.json( { subject: query.resource, links: bot.links - }); -}); + } ); +} ); module.exports = router; diff --git a/server.js b/server.js index 44ceb58..d12ec1e 100644 --- a/server.js +++ b/server.js @@ -1,25 +1,37 @@ -var app = require(__dirname + '/app.js'), - load_keys = require(__dirname + '/helpers/keys.js'), - db = require(__dirname + '/helpers/db.js'); +const app = require( __dirname + '/app.js' ), + load_keys = require( __dirname + '/helpers/keys.js' ), + db = require( __dirname + '/helpers/db.js' ), + bot = require(__dirname + '/bot/bot.js'), + CronJob = require( 'cron' ).CronJob, + cronSchedules = require( __dirname + '/helpers/cron-schedules.js' ); db.init(); -// db.dropTable('Posts'); -// db.dropTable('Followers'); -// db.dropTable('Events'); +// db.dropTable( 'Posts' ); +// db.dropTable( 'Followers' ); +// db.dropTable( 'Events' ); -// db.getFollowers(function(err, data){ -// console.log('Followers:', data); -// }); +// db.getFollowers( function( err, data ){ +// console.log( 'Followers:', data ); +// } ); -// db.getPosts(function(err, data){ -// console.log('Posts:', data); -// }); +// db.getPosts( function( err, data ){ +// console.log( 'Posts:', data ); +// } ); -// db.getEvents(function(err, data){ -// console.log('Events:', data); -// }); +// db.getEvents( function( err, data ){ +// console.log( 'Events:', data ); +// } ); -var listener = app.listen(process.env.PORT, function() { - console.log(`app is running on port ${listener.address().port}...`); +// const job = new CronJob( cronSchedules.EVERY_SIX_HOURS, function() { bot.script() } ); +const job = new CronJob( cronSchedules.EVERY_FIVE_SECONDS, function() { bot.script() } ); + +// job.start(); + +bot.script(); + + + +const listener = app.listen(process.env.PORT, function(){ + console.log( `app is running on port ${listener.address().port}...` ); }); diff --git a/shrinkwrap.yaml b/shrinkwrap.yaml index 8049d9f..c7fa5aa 100644 --- a/shrinkwrap.yaml +++ b/shrinkwrap.yaml @@ -4,6 +4,7 @@ dependencies: canvas: 2.0.0-alpha.17 color-scheme: 1.0.1 connect-sqlite3: 0.9.11 + cron: 1.8.2 express: 4.16.3 express-babelify-middleware: 0.2.1 express-handlebars: 3.0.0 @@ -1441,6 +1442,12 @@ packages: dev: false resolution: integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + /cron/1.8.2: + dependencies: + moment-timezone: 0.5.31 + dev: false + resolution: + integrity: sha512-Gk2c4y6xKEO8FSAUTklqtfSr7oTq0CiPQeLBG5Fl0qoXpZyMcj1SG59YL+hqq04bu6/IuEA7lMkYDAplQNKkyg== /cross-spawn/3.0.1: dependencies: lru-cache: 4.1.3 @@ -3301,10 +3308,20 @@ packages: hasBin: true resolution: integrity: sha512-NPs5N511VD1rrVJihSso/LiBShRbJALYBKzDW91uZYy7BpjnO4bGnZL3HjZ9yKcFdZUWwaYjDz9zxbuP7vKMuQ== + /moment-timezone/0.5.31: + dependencies: + moment: 2.27.0 + dev: false + resolution: + integrity: sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA== /moment/2.22.2: dev: false resolution: integrity: sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y= + /moment/2.27.0: + dev: false + resolution: + integrity: sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ== /momentjs/2.0.0: deprecated: 'WARNING: The correct package name for Moment.js is ''moment'', not ''momentjs''.' dev: false @@ -5361,6 +5378,7 @@ specifiers: canvas: ^2.0.0-alpha.17 color-scheme: ^1.0.1 connect-sqlite3: ^0.9.11 + cron: ^1.8.2 express: ^4.16.3 express-babelify-middleware: ^0.2.1 express-handlebars: ^3.0.0 diff --git a/src/scripts/scripts.js b/src/scripts/scripts.js index 445efb4..269817f 100644 --- a/src/scripts/scripts.js +++ b/src/scripts/scripts.js @@ -8,4 +8,16 @@ return confirm(confirmActionText); }); + $( '.post-date' ).each( function(){ + let $date = $( this ); + const date = $date.attr( 'title' ); + $date.attr( 'title', moment( moment.utc( date ).toDate() ).local().format( 'YYYY-MM-DD HH:mm:ss' ) ); + } ); + + $( '.post-date-formatted' ).each( function(){ + let $date = $( this ); + const date = $date.html(); + $date.html( moment( moment.utc( date ).toDate() ).local().format( 'YYYY-MM-DD HH:mm:ss' ) ); + } ); + })(jQuery); diff --git a/views/layouts/main.handlebars b/views/layouts/main.handlebars index c74dd82..70fb23b 100644 --- a/views/layouts/main.handlebars +++ b/views/layouts/main.handlebars @@ -63,6 +63,7 @@ src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"> + diff --git a/views/post.handlebars b/views/post.handlebars index 404b81d..a7c13f6 100644 --- a/views/post.handlebars +++ b/views/post.handlebars @@ -3,7 +3,7 @@
{{#equals post.type "Note"}}
-
{{post.date}}
+ {{#if post.content}}

{{{post.content}}}

{{/if}}