├── RedSnap ├── RedSnap │ ├── bin │ │ ├── node.cmd │ │ ├── www │ │ ├── ChangeConfig.ps1 │ │ ├── setup_web.cmd │ │ └── download.ps1 │ ├── IISNode.yml │ ├── public │ │ ├── views │ │ │ ├── logout.html │ │ │ ├── cam │ │ │ │ ├── snapcanvas.html │ │ │ │ ├── view.html │ │ │ │ └── draw.html │ │ │ ├── main.html │ │ │ ├── snapModal.html │ │ │ ├── register.html │ │ │ ├── friends.html │ │ │ └── login.html │ │ ├── images │ │ │ ├── snap.png │ │ │ ├── favicon.ico │ │ │ └── spinner.gif │ │ ├── stylesheets │ │ │ ├── style.styl │ │ │ └── style.css │ │ ├── javascripts │ │ │ ├── services │ │ │ │ ├── Snap.js │ │ │ │ ├── Friend.js │ │ │ │ ├── Session.js │ │ │ │ ├── SnapView.js │ │ │ │ ├── User.js │ │ │ │ ├── SnapService.js │ │ │ │ ├── FriendService.js │ │ │ │ ├── Auth.js │ │ │ │ └── http-auth-interceptor.js │ │ │ ├── controllers │ │ │ │ ├── cam.js │ │ │ │ ├── logout.js │ │ │ │ ├── register.js │ │ │ │ ├── login.js │ │ │ │ ├── friends.js │ │ │ │ ├── cam │ │ │ │ │ ├── view.js │ │ │ │ │ └── draw.js │ │ │ │ └── main.js │ │ │ ├── directives │ │ │ │ ├── canvas.js │ │ │ │ └── webcam.js │ │ │ ├── core.js │ │ │ └── providers │ │ │ │ └── socket.js │ │ └── index.html │ ├── obj │ │ └── Release │ │ │ └── Package │ │ │ └── PackageTmp │ │ │ └── public │ │ │ ├── views │ │ │ ├── logout.html │ │ │ ├── cam │ │ │ │ ├── snapcanvas.html │ │ │ │ ├── view.html │ │ │ │ └── draw.html │ │ │ ├── main.html │ │ │ ├── snapModal.html │ │ │ ├── register.html │ │ │ ├── friends.html │ │ │ └── login.html │ │ │ ├── images │ │ │ ├── snap.png │ │ │ ├── favicon.ico │ │ │ └── spinner.gif │ │ │ ├── javascripts │ │ │ ├── services │ │ │ │ ├── Snap.js │ │ │ │ ├── Friend.js │ │ │ │ ├── Session.js │ │ │ │ ├── SnapView.js │ │ │ │ ├── User.js │ │ │ │ ├── SnapService.js │ │ │ │ ├── FriendService.js │ │ │ │ ├── Auth.js │ │ │ │ └── http-auth-interceptor.js │ │ │ ├── controllers │ │ │ │ ├── cam.js │ │ │ │ ├── logout.js │ │ │ │ ├── register.js │ │ │ │ ├── login.js │ │ │ │ ├── friends.js │ │ │ │ ├── cam │ │ │ │ │ ├── view.js │ │ │ │ │ └── draw.js │ │ │ │ └── main.js │ │ │ ├── directives │ │ │ │ ├── canvas.js │ │ │ │ └── webcam.js │ │ │ ├── core.js │ │ │ └── providers │ │ │ │ └── socket.js │ │ │ ├── stylesheets │ │ │ └── style.styl │ │ │ └── index.html │ ├── controllers │ │ ├── socket.js │ │ ├── session.js │ │ ├── user.js │ │ └── snap.js │ ├── systems │ │ ├── rediscon.js │ │ ├── auth.js │ │ ├── nocache.js │ │ ├── imagepurge.js │ │ └── pass.js │ ├── package.json │ ├── Web.Debug.config │ ├── app.js │ ├── Web.config │ ├── models │ │ └── User.js │ ├── routes.js │ └── RedSnap.njsproj └── RedSnap.sln ├── .gitignore ├── LICENSE ├── .gitattributes └── README.md /RedSnap/RedSnap/bin/node.cmd: -------------------------------------------------------------------------------- 1 | node.exe %1 %2 %3 -------------------------------------------------------------------------------- /RedSnap/RedSnap/IISNode.yml: -------------------------------------------------------------------------------- 1 | loggingEnabled: true 2 | devErrorsEnabled: true -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/views/logout.html: -------------------------------------------------------------------------------- 1 |

You have been logged out

2 |

You will be redirected shortly.

-------------------------------------------------------------------------------- /RedSnap/RedSnap/public/views/cam/snapcanvas.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
-------------------------------------------------------------------------------- /RedSnap/RedSnap/public/images/snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaessaki/RedSnap/HEAD/RedSnap/RedSnap/public/images/snap.png -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaessaki/RedSnap/HEAD/RedSnap/RedSnap/public/images/favicon.ico -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/images/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaessaki/RedSnap/HEAD/RedSnap/RedSnap/public/images/spinner.gif -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/views/logout.html: -------------------------------------------------------------------------------- 1 |

You have been logged out

2 |

You will be redirected shortly.

-------------------------------------------------------------------------------- /RedSnap/RedSnap/controllers/socket.js: -------------------------------------------------------------------------------- 1 | module.exports = function (socket) { 2 | 3 | socket.on('new snap', function (data) { 4 | 5 | }) 6 | 7 | } -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/views/cam/snapcanvas.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
-------------------------------------------------------------------------------- /RedSnap/RedSnap/public/stylesheets/style.styl: -------------------------------------------------------------------------------- 1 | body 2 | padding: 50px 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif 4 | a 5 | color: #00B7FF -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/images/snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaessaki/RedSnap/HEAD/RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/images/snap.png -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaessaki/RedSnap/HEAD/RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/images/favicon.ico -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/images/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaessaki/RedSnap/HEAD/RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/images/spinner.gif -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/services/Snap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('RedSnap') 4 | .factory('Snap', function ($resource) { 5 | return $resource('/api/snaps/'); 6 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/systems/rediscon.js: -------------------------------------------------------------------------------- 1 | var redis = require('redis'); 2 | 3 | var config = require('../config.js'); 4 | 5 | module.exports = redis.createClient({ 6 | url: config.redisURL 7 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/services/Friend.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('RedSnap') 4 | .factory('Friend', function ($resource) { 5 | return $resource('/api/friends/'); 6 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/services/Session.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('RedSnap') 4 | .factory('Session', function ($resource) { 5 | return $resource('/auth/session/'); 6 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/services/SnapView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('RedSnap') 4 | .factory('SnapView', function ($resource) { 5 | return $resource('/api/snaps/view'); 6 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/services/Snap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('RedSnap') 4 | .factory('Snap', function ($resource) { 5 | return $resource('/api/snaps/'); 6 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/services/Friend.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('RedSnap') 4 | .factory('Friend', function ($resource) { 5 | return $resource('/api/friends/'); 6 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/controllers/cam.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | .controller('camController', function ($scope) { 3 | $scope.snapImage = {} 4 | $scope.snapWidth = {} 5 | $scope.snapHeight = {} 6 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/services/Session.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('RedSnap') 4 | .factory('Session', function ($resource) { 5 | return $resource('/auth/session/'); 6 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/services/SnapView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('RedSnap') 4 | .factory('SnapView', function ($resource) { 5 | return $resource('/api/snaps/view'); 6 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/systems/auth.js: -------------------------------------------------------------------------------- 1 | //passport middleware to ensure user is authenticated 2 | exports.ensureAuthenticated = function ensureAuthenticated(req, res, next) { 3 | if (req.isAuthenticated()) { return next(); } 4 | res.send(401); 5 | } -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/controllers/cam.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | .controller('camController', function ($scope) { 3 | $scope.snapImage = {} 4 | $scope.snapWidth = {} 5 | $scope.snapHeight = {} 6 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/services/User.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('RedSnap') 4 | .factory('User', function ($resource) { 5 | return $resource('/auth/users/:id/', {}, 6 | { 7 | 'update': { 8 | method: 'PUT' 9 | } 10 | }); 11 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var debug = require('debug')('RedSnap'); 3 | var app = require('../app'); 4 | 5 | app.set('port', process.env.PORT || 3000); 6 | 7 | var server = app.listen(app.get('port'), function() { 8 | debug('Express server listening on port ' + server.address().port); 9 | }); 10 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/services/User.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('RedSnap') 4 | .factory('User', function ($resource) { 5 | return $resource('/auth/users/:id/', {}, 6 | { 7 | 'update': { 8 | method: 'PUT' 9 | } 10 | }); 11 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/systems/nocache.js: -------------------------------------------------------------------------------- 1 | 2 | //Edge caches GET requests so we need to nocache whenver Angular GETS new data in regards to friends and the like 3 | module.exports = function nocache(req, res, next) { 4 | res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate'); 5 | res.header('Expires', '-1'); 6 | res.header('Pragma', 'no-cache'); 7 | next(); 8 | } -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/views/cam/view.html: -------------------------------------------------------------------------------- 1 |
2 | 8 | 9 | 10 |
-------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/controllers/logout.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | 3 | .controller('logoutController', function ($scope, $rootScope, $timeout, $state, Auth) { 4 | $scope.user = {} 5 | Auth.logout(function (err) { 6 | console.log(err); 7 | }) 8 | $rootScope.loggedIn = false; //Solely used to toggle ng-show 9 | $timeout( 10 | function () { 11 | $state.go('login') 12 | }, 2500); 13 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/views/cam/view.html: -------------------------------------------------------------------------------- 1 |
2 | 8 | 9 | 10 |
-------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/controllers/logout.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | 3 | .controller('logoutController', function ($scope, $rootScope, $timeout, $state, Auth) { 4 | $scope.user = {} 5 | Auth.logout(function (err) { 6 | console.log(err); 7 | }) 8 | $rootScope.loggedIn = false; //Solely used to toggle ng-show 9 | $timeout( 10 | function () { 11 | $state.go('login') 12 | }, 2500); 13 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/views/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 12 | 13 | 14 |
5 | 8 | 10 |
{{ snap.sender }}
11 |
15 | 16 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/views/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 12 | 13 | 14 |
5 | 8 | 10 |
{{ snap.sender }}
11 |
15 | 16 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/views/snapModal.html: -------------------------------------------------------------------------------- 1 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/views/snapModal.html: -------------------------------------------------------------------------------- 1 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/controllers/register.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | 3 | .controller('registerController', function ($location, $scope, Auth) { 4 | $scope.formData = {}; 5 | 6 | $scope.register = function () { 7 | if ($scope.formData.username != undefined) { 8 | Auth.register($scope.formData, function (err) { 9 | $scope.errors= {} 10 | 11 | if (!err) { 12 | $location.path('/') 13 | } 14 | else { 15 | console.log(err) 16 | 17 | } 18 | }); 19 | 20 | } 21 | } 22 | 23 | }); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/bin/ChangeConfig.ps1: -------------------------------------------------------------------------------- 1 | $configFile = $args[0] 2 | 3 | Write-Host "Adding iisnode section to config file '$configFile'" 4 | $config = New-Object System.Xml.XmlDocument 5 | $config.load($configFile) 6 | $xpath = $config.CreateNavigator() 7 | $parentElement = $xpath.SelectSingleNode("//configuration/configSections/sectionGroup[@name='system.webServer']") 8 | $iisnodeElement = $parentElement.SelectSingleNode("//section[@name='iisnode']") 9 | if ($iisnodeElement) { 10 | Write-Host "Removing existing iisnode section from config file '$configFile'" 11 | $iisnodeElement.DeleteSelf() 12 | } 13 | 14 | $parentElement.AppendChild("
") 15 | $config.Save($configFile) 16 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/controllers/register.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | 3 | .controller('registerController', function ($location, $scope, Auth) { 4 | $scope.formData = {}; 5 | 6 | $scope.register = function () { 7 | if ($scope.formData.username != undefined) { 8 | Auth.register($scope.formData, function (err) { 9 | $scope.errors= {} 10 | 11 | if (!err) { 12 | $location.path('/') 13 | } 14 | else { 15 | console.log(err) 16 | 17 | } 18 | }); 19 | 20 | } 21 | } 22 | 23 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/systems/imagepurge.js: -------------------------------------------------------------------------------- 1 | //cron job that deletes photos that have all been played 2 | var CronJob = require('cron').CronJob; 3 | var redis = require('redis'); 4 | var client = require('../systems/rediscon.js'); 5 | var async = require('async') 6 | 7 | module.exports = new CronJob('00 00 4 * * 0-6', function () { 8 | 9 | client.lrange('deletion', 0, -1, function (err, reply) { 10 | 11 | async.each(reply, function (snap_id, cb) { 12 | 13 | //delete from filesystem 14 | //delete snap data from redis 15 | //call cronjob from app.js 16 | 17 | //Weird, I'm pretty sure I implemented this, but for some reason it's not on Github. Will have to check where the code went 18 | 19 | }, function (err) { 20 | 21 | }) 22 | 23 | }) 24 | }); 25 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/directives/canvas.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | .directive('snapcanvas', function () { 3 | return { 4 | templateUrl: 'views/cam/snapcanvas.html', 5 | replace: true, 6 | restrict: 'AE', 7 | scope: { 8 | config: '=conf' 9 | }, 10 | link: function postLink($scope, elm) { 11 | 12 | var conf = $scope.$parent.conf; 13 | var c = document.createElement('canvas'); 14 | var att = document.createAttribute("id"); 15 | att.value = 'snapcan'; 16 | c.setAttributeNode(att); 17 | 18 | c.width = conf.width; 19 | c.height = conf.height; 20 | 21 | var ctx = c.getContext('2d') 22 | ctx.putImageData(conf.imageData, 0, 0) 23 | 24 | angular.element(c).css("width", "100%") 25 | 26 | elm.find('div').append(c); 27 | 28 | } 29 | 30 | } 31 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/controllers/login.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | .controller('loginController', function ($scope, $rootScope, Auth, $location) { 3 | $scope.user = {}; 4 | 5 | $scope.login = function () { 6 | console.log('attempting log in') 7 | Auth.login($scope.user, 8 | function (err) { 9 | $scope.errors = []; 10 | 11 | if (!err) { 12 | $rootScope.loggedIn = true; 13 | $location.path('/'); 14 | } else { 15 | angular.forEach(err.errors, function (error, key) { 16 | $scope.errors.push(error) 17 | }) 18 | //angular.forEach(err.errors, function (error, field) { 19 | // form[field].$setValidity('mongoose', false); 20 | // $scope.errors[field] = error.type; 21 | //}); 22 | } 23 | }); 24 | }; 25 | }); 26 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RedSnap", 3 | "version": "0.2.2", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "description": "An open-source browser-based Snapchat clone", 9 | "author": { 10 | "name": "Mansib Rahman", 11 | "email": "mansib.rahman@outlook.com" 12 | }, 13 | "dependencies": { 14 | "async": "1.5.2", 15 | "body-parser": "~1.8.1", 16 | "connect-redis": "*", 17 | "cookie-parser": "~1.3.3", 18 | "cron": "1.1.0", 19 | "crypto": "*", 20 | "debug": "~2.0.0", 21 | "express": "~4.9.0", 22 | "express-session": "*", 23 | "kerberos": "*", 24 | "mkdirp": "0.5.1", 25 | "mongoose": "^4.4.3", 26 | "morgan": "~1.3.0", 27 | "node-uuid": "*", 28 | "passport": "*", 29 | "passport-local": "*", 30 | "path": "*", 31 | "redis-session": "*", 32 | "serve-favicon": "~2.1.3", 33 | "socket.io": "*", 34 | "stylus": "0.42.3" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/directives/canvas.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | .directive('snapcanvas', function () { 3 | return { 4 | templateUrl: 'views/cam/snapcanvas.html', 5 | replace: true, 6 | restrict: 'AE', 7 | scope: { 8 | config: '=conf' 9 | }, 10 | link: function postLink($scope, elm) { 11 | 12 | var conf = $scope.$parent.conf; 13 | var c = document.createElement('canvas'); 14 | var att = document.createAttribute("id"); 15 | att.value = 'snapcan'; 16 | c.setAttributeNode(att); 17 | 18 | c.width = conf.width; 19 | c.height = conf.height; 20 | 21 | var ctx = c.getContext('2d') 22 | ctx.putImageData(conf.imageData, 0, 0) 23 | 24 | angular.element(c).css("width", "100%") 25 | 26 | elm.find('div').append(c); 27 | 28 | } 29 | 30 | } 31 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/controllers/login.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | .controller('loginController', function ($scope, $rootScope, Auth, $location) { 3 | $scope.user = {}; 4 | 5 | $scope.login = function () { 6 | console.log('attempting log in') 7 | Auth.login($scope.user, 8 | function (err) { 9 | $scope.errors = []; 10 | 11 | if (!err) { 12 | $rootScope.loggedIn = true; 13 | $location.path('/'); 14 | } else { 15 | angular.forEach(err.errors, function (error, key) { 16 | $scope.errors.push(error) 17 | }) 18 | //angular.forEach(err.errors, function (error, field) { 19 | // form[field].$setValidity('mongoose', false); 20 | // $scope.errors[field] = error.type; 21 | //}); 22 | } 23 | }); 24 | }; 25 | }); 26 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/views/register.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 |
7 |
8 | 9 | 10 |
11 |
12 | 13 | 14 |
15 | 16 |
-------------------------------------------------------------------------------- /RedSnap/RedSnap/controllers/session.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var passport = require('passport'); 4 | 5 | exports.session = function (req, res) { 6 | res.json(req.user.user_info); 7 | }; 8 | 9 | exports.logout = function (req, res) { 10 | if (req.user) { 11 | req.logout(); 12 | res.send(200); 13 | } else { 14 | res.send(400, "Not logged in"); 15 | } 16 | }; 17 | 18 | exports.login = function (req, res, next) { 19 | passport.authenticate('local', function (err, user, info) { 20 | var error = err || info; 21 | if (error) { 22 | console.log(error) 23 | return res.status(404).send(error); 24 | } 25 | req.logIn(user, function (err) { 26 | if (err) { 27 | console.log(error) 28 | res.status(404).send(error); 29 | } 30 | else { 31 | console.log(req.user) 32 | res.send(req.user.user_info); 33 | } 34 | }); 35 | })(req, res, next); 36 | } 37 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/services/SnapService.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('RedSnap') 4 | .factory('SnapService', function SnapService(Snap, SnapView) { 5 | 6 | return { 7 | sendSnap: function (snapData, callback) { 8 | var cb = callback || angular.noop; 9 | Snap.save({ 10 | snap: snapData 11 | }, 12 | function (err) { 13 | console.log(err.data); 14 | return cb(err.data); 15 | }) 16 | }, 17 | viewSnap: function (snapData, callback) { 18 | var cb = callback || angular.noop; 19 | SnapView.save({ 20 | snapInfo: snapData 21 | }, function (snap) { 22 | return cb(snap); 23 | }) 24 | }, 25 | listSnaps: function (callback) { 26 | var cb = callback || angular.noop; 27 | Snap.query(function (snaps) { 28 | return cb(snaps); 29 | }) 30 | } 31 | } 32 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/views/register.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 |
7 |
8 | 9 | 10 |
11 |
12 | 13 | 14 |
15 | 16 |
-------------------------------------------------------------------------------- /RedSnap/RedSnap.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "RedSnap", "RedSnap\RedSnap.njsproj", "{DA47B884-6324-463E-BF38-692F7F7A3F32}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {DA47B884-6324-463E-BF38-692F7F7A3F32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {DA47B884-6324-463E-BF38-692F7F7A3F32}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {DA47B884-6324-463E-BF38-692F7F7A3F32}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {DA47B884-6324-463E-BF38-692F7F7A3F32}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/services/SnapService.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('RedSnap') 4 | .factory('SnapService', function SnapService(Snap, SnapView) { 5 | 6 | return { 7 | sendSnap: function (snapData, callback) { 8 | var cb = callback || angular.noop; 9 | Snap.save({ 10 | snap: snapData 11 | }, 12 | function (err) { 13 | console.log(err.data); 14 | return cb(err.data); 15 | }) 16 | }, 17 | viewSnap: function (snapData, callback) { 18 | var cb = callback || angular.noop; 19 | SnapView.save({ 20 | snapInfo: snapData 21 | }, function (snap) { 22 | return cb(snap); 23 | }) 24 | }, 25 | listSnaps: function (callback) { 26 | var cb = callback || angular.noop; 27 | Snap.query(function (snaps) { 28 | return cb(snaps); 29 | }) 30 | } 31 | } 32 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/controllers/friends.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | 3 | .controller('friendsController', function ($scope, $timeout, FriendService) { 4 | $scope.friends = {} 5 | $scope.potentialfriend = "" 6 | FriendService.listFriends(function (friends) { 7 | $scope.friends = friends; 8 | }) 9 | 10 | $scope.befriend = function (friend) { 11 | $scope.potentialfriend = "" 12 | FriendService.addFriend(friend, function (err, friends) { 13 | if (err) { 14 | $scope.msg = err; 15 | } 16 | if (friends) { 17 | $scope.msg = "Friend request sent and/or friend added" 18 | $scope.friends = friends; 19 | $timeout(function () { 20 | $scope.msg = ""; 21 | }, 3500) 22 | } 23 | }) 24 | 25 | } 26 | $scope.unfriend = function (friend) { 27 | FriendService.removeFriend(friend, function (err, friends) { 28 | if (err) console.log(err) 29 | if (friends) $scope.friends = friends; 30 | }) 31 | } 32 | }) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Mansib 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/controllers/friends.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | 3 | .controller('friendsController', function ($scope, $timeout, FriendService) { 4 | $scope.friends = {} 5 | $scope.potentialfriend = "" 6 | FriendService.listFriends(function (friends) { 7 | $scope.friends = friends; 8 | }) 9 | 10 | $scope.befriend = function (friend) { 11 | $scope.potentialfriend = "" 12 | FriendService.addFriend(friend, function (err, friends) { 13 | if (err) { 14 | $scope.msg = err; 15 | } 16 | if (friends) { 17 | $scope.msg = "Friend request sent and/or friend added" 18 | $scope.friends = friends; 19 | $timeout(function () { 20 | $scope.msg = ""; 21 | }, 3500) 22 | } 23 | }) 24 | 25 | } 26 | $scope.unfriend = function (friend) { 27 | FriendService.removeFriend(friend, function (err, friends) { 28 | if (err) console.log(err) 29 | if (friends) $scope.friends = friends; 30 | }) 31 | } 32 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/controllers/cam/view.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | 3 | .controller('camViewController', function ($scope, $state) { 4 | 5 | var _video = null; 6 | $scope.channel = { 7 | videoWidth: 640, 8 | videoHeight: 480 9 | }; 10 | 11 | $scope.webcamError = false; 12 | $scope.onError = function (err) { 13 | $scope.$apply(function () { 14 | $scope.webcamError = err; 15 | }) 16 | }; 17 | $scope.onStream = function (stream) { 18 | _video = $scope.channel.video; 19 | }; 20 | $scope.onSuccess = function () { }; 21 | 22 | $scope.snap = function () { 23 | if (_video) { 24 | var idata = getVideoData(0, 0, _video.width, _video.height); 25 | $scope.$parent.snapImage = idata 26 | $scope.$parent.snapWidth = _video.width; 27 | $scope.$parent.snapHeight = _video.height; 28 | $state.go('cam.draw') 29 | } 30 | } 31 | 32 | var getVideoData = function getVideoData(x, y, w, h) { 33 | var c = document.createElement('canvas'); 34 | c.width = w; 35 | c.height = h; 36 | var ctx = c.getContext('2d'); 37 | ctx.drawImage(_video, 0, 0); 38 | return ctx.getImageData(x, y, w, h); 39 | } 40 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/controllers/cam/view.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | 3 | .controller('camViewController', function ($scope, $state) { 4 | 5 | var _video = null; 6 | $scope.channel = { 7 | videoWidth: 640, 8 | videoHeight: 480 9 | }; 10 | 11 | $scope.webcamError = false; 12 | $scope.onError = function (err) { 13 | $scope.$apply(function () { 14 | $scope.webcamError = err; 15 | }) 16 | }; 17 | $scope.onStream = function (stream) { 18 | _video = $scope.channel.video; 19 | }; 20 | $scope.onSuccess = function () { }; 21 | 22 | $scope.snap = function () { 23 | if (_video) { 24 | var idata = getVideoData(0, 0, _video.width, _video.height); 25 | $scope.$parent.snapImage = idata 26 | $scope.$parent.snapWidth = _video.width; 27 | $scope.$parent.snapHeight = _video.height; 28 | $state.go('cam.draw') 29 | } 30 | } 31 | 32 | var getVideoData = function getVideoData(x, y, w, h) { 33 | var c = document.createElement('canvas'); 34 | c.width = w; 35 | c.height = h; 36 | var ctx = c.getContext('2d'); 37 | ctx.drawImage(_video, 0, 0); 38 | return ctx.getImageData(x, y, w, h); 39 | } 40 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/systems/pass.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'), 2 | passport = require('passport'), 3 | LocalStrategy = require('passport-local').Strategy, 4 | User = mongoose.model('User'); 5 | 6 | // Serialize sessions 7 | passport.serializeUser(function (user, done) { 8 | done(null, user.id); 9 | }); 10 | 11 | passport.deserializeUser(function (id, done) { 12 | User.findOne({ _id: id }, function (err, user) { 13 | done(err, user); 14 | }); 15 | }); 16 | 17 | // Use local strategy 18 | passport.use(new LocalStrategy({ 19 | usernameField: 'username', 20 | passwordField: 'password' 21 | }, 22 | function (username, password, done) { 23 | console.log("attempting to find user") 24 | User.findOne({ username: username }, function (err, user) { 25 | if (err) { 26 | return done(err); 27 | } 28 | if (!user) { 29 | return done(null, false, { 30 | 'errors': { 31 | 'username': { type: 'Username is not registered.' } 32 | } 33 | }); 34 | } 35 | if (!user.authenticate(password)) { 36 | return done(null, false, { 37 | 'errors': { 38 | 'password': { type: 'Password is incorrect.' } 39 | } 40 | }); 41 | } 42 | console.log("found user") 43 | return done(null, user); 44 | }); 45 | } 46 | )); 47 | 48 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/views/friends.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 12 | 13 | 14 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 32 | 33 | 34 | 35 |
5 | 6 | 8 | 11 |
15 |
{{ msg }}
16 |
20 | 23 |
{{ friend.username }}
28 | 31 |
{{ friend.username }}
-------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/views/friends.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 12 | 13 | 14 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 32 | 33 | 34 | 35 |
5 | 6 | 8 | 11 |
15 |
{{ msg }}
16 |
20 | 23 |
{{ friend.username }}
28 | 31 |
{{ friend.username }}
-------------------------------------------------------------------------------- /RedSnap/RedSnap/public/views/login.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 |
7 |
8 | 9 | 10 |
11 | 12 |
13 |
14 |

{{ error.type }}

15 |
16 |
17 |

RedSnap

18 |

An open-source web-based Snapchat clone. Built with node.js, express.js, angular, mongodb and redis.

19 |

20 | 21 | Historically, privacy was almost implicit, because it was hard to find and gather information. But in the digital world, whether it’s digital cameras or satellites or just what you click on, we need to have more explicit rules—not just for governments but for private companies. —Bill Gates 22 | 23 |

24 |

v 0.2.2 Code license MIT (c) 2016 —@gaessaki

25 |
-------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/views/login.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 |
7 |
8 | 9 | 10 |
11 | 12 |
13 |
14 |

{{ error.type }}

15 |
16 |
17 |

RedSnap

18 |

An open-source web-based Snapchat clone. Built with node.js, express.js, angular, mongodb and redis.

19 |

20 | 21 | Historically, privacy was almost implicit, because it was hard to find and gather information. But in the digital world, whether it’s digital cameras or satellites or just what you click on, we need to have more explicit rules—not just for governments but for private companies. —Bill Gates 22 | 23 |

24 |

v 0.2.2 Code license MIT (c) 2016 —@gaessaki

25 |
-------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/services/FriendService.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('RedSnap') 4 | .factory('FriendService', function FriendService(Friend) { 5 | 6 | return { 7 | addFriend: function (friendName, callback) { 8 | var cb = callback || angular.noop; 9 | Friend.save({ 10 | friend: friendName 11 | }, function () { 12 | Friend.get(function (friends) { 13 | return cb(null, friends); 14 | }) 15 | }, 16 | function (err) { 17 | console.log(err.data); 18 | Friend.get(function (friends) { 19 | return cb(err.data, friends); 20 | }) 21 | return cb(err.data, null); 22 | }) 23 | }, 24 | removeFriend: function (friendName, callback) { 25 | var cb = callback || angular.noop; 26 | Friend.remove({ 27 | friend: friendName 28 | }, function () { 29 | Friend.get(function (friends) { 30 | return cb(null, friends); 31 | }) 32 | }), 33 | function (err) { 34 | console.log(err.data); 35 | Friend.get(function (friends) { 36 | return cb(err.data, friends); 37 | }) 38 | return cb(err.data, null); 39 | } 40 | }, 41 | listFriends: function (callback) { 42 | var cb = callback || angular.noop; 43 | Friend.get(function (friends) { 44 | return cb(friends); 45 | }) 46 | } 47 | } 48 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/services/FriendService.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('RedSnap') 4 | .factory('FriendService', function FriendService(Friend) { 5 | 6 | return { 7 | addFriend: function (friendName, callback) { 8 | var cb = callback || angular.noop; 9 | Friend.save({ 10 | friend: friendName 11 | }, function () { 12 | Friend.get(function (friends) { 13 | return cb(null, friends); 14 | }) 15 | }, 16 | function (err) { 17 | console.log(err.data); 18 | Friend.get(function (friends) { 19 | return cb(err.data, friends); 20 | }) 21 | return cb(err.data, null); 22 | }) 23 | }, 24 | removeFriend: function (friendName, callback) { 25 | var cb = callback || angular.noop; 26 | Friend.remove({ 27 | friend: friendName 28 | }, function () { 29 | Friend.get(function (friends) { 30 | return cb(null, friends); 31 | }) 32 | }), 33 | function (err) { 34 | console.log(err.data); 35 | Friend.get(function (friends) { 36 | return cb(err.data, friends); 37 | }) 38 | return cb(err.data, null); 39 | } 40 | }, 41 | listFriends: function (callback) { 42 | var cb = callback || angular.noop; 43 | Friend.get(function (friends) { 44 | return cb(friends); 45 | }) 46 | } 47 | } 48 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/views/cam/draw.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 |
8 | 9 |
10 |
11 | 13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Send To... 21 |
22 | 23 | 24 | 25 | 31 | 32 | 33 |
26 |
27 | 28 | 29 |
30 |
34 | 38 |
39 |

40 | 41 |

42 |
43 | 44 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/views/cam/draw.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 |
8 | 9 |
10 |
11 | 13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Send To... 21 |
22 | 23 | 24 | 25 | 31 | 32 | 33 |
26 |
27 | 28 | 29 |
30 |
34 | 38 |
39 |

40 | 41 |

42 |
43 | 44 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/bin/setup_web.cmd: -------------------------------------------------------------------------------- 1 | @echo on 2 | 3 | cd /d "%~dp0" 4 | 5 | if "%EMULATED%"=="true" if DEFINED APPCMD goto emulator_setup 6 | if "%EMULATED%"== "true" exit /b 0 7 | 8 | echo Granting permissions for Network Service to the web root directory... 9 | icacls ..\ /grant "Network Service":(OI)(CI)W 10 | if %ERRORLEVEL% neq 0 goto error 11 | echo OK 12 | 13 | echo Configuring powershell permissions 14 | powershell -c "set-executionpolicy unrestricted" 15 | 16 | echo Downloading and installing runtime components 17 | powershell .\download.ps1 '%RUNTIMEURL%' '%RUNTIMEURLOVERRIDE%' 18 | if %ERRORLEVEL% neq 0 goto error 19 | 20 | echo SUCCESS 21 | exit /b 0 22 | 23 | :error 24 | echo FAILED 25 | exit /b -1 26 | 27 | :emulator_setup 28 | echo Running in emulator adding iisnode to application host config 29 | FOR /F "tokens=1,2 delims=/" %%a in ("%APPCMD%") DO set FN=%%a&set OPN=%%b 30 | if "%OPN%"=="%OPN:apphostconfig:=%" ( 31 | echo "Could not parse appcmd '%appcmd% for configuration file, exiting" 32 | goto error 33 | ) 34 | 35 | set IISNODE_BINARY_DIRECTORY=%programfiles(x86)%\iisnode-dev\release\x64 36 | set IISNODE_SCHEMA=%programfiles(x86)%\iisnode-dev\release\x64\iisnode_schema.xml 37 | 38 | if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto start 39 | set IISNODE_BINARY_DIRECTORY=%programfiles%\iisnode-dev\release\x86 40 | set IISNODE_SCHEMA=%programfiles%\iisnode-dev\release\x86\iisnode_schema_x86.xml 41 | 42 | 43 | :start 44 | set 45 | 46 | echo Using iisnode binaries location '%IISNODE_BINARY_DIRECTORY%' 47 | echo installing iisnode module using AppCMD alias %appcmd% 48 | %appcmd% install module /name:"iisnode" /image:"%IISNODE_BINARY_DIRECTORY%\iisnode.dll" 49 | 50 | set apphostconfigfile=%OPN:apphostconfig:=% 51 | powershell -c "set-executionpolicy unrestricted" 52 | powershell .\ChangeConfig.ps1 %apphostconfigfile% 53 | if %ERRORLEVEL% neq 0 goto error 54 | 55 | copy /y "%IISNODE_SCHEMA%" "%programfiles%\IIS Express\config\schema\iisnode_schema.xml" 56 | if %ERRORLEVEL% neq 0 goto error 57 | exit /b 0 58 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/services/Auth.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('RedSnap') 4 | .factory('Auth', function Auth($rootScope, User, Session, $cookieStore) { 5 | $rootScope.currentUser = $cookieStore.get('user') || null; 6 | $cookieStore.remove('user'); 7 | 8 | return { 9 | 10 | login: function (userData, callback) { 11 | var cb = callback || angular.noop; 12 | Session.save({ 13 | username: userData.username, 14 | password: userData.password 15 | }, 16 | function (user) { 17 | $rootScope.curentUser = user 18 | return cb(); 19 | }, 20 | function (err) { 21 | console.log(err.data) 22 | return cb(err.data); 23 | }) 24 | }, 25 | logout: function (callback) { 26 | var cb = callback || angular.noop; 27 | Session.delete(function (res) { 28 | $rootScope.curentUser = null; 29 | return cb(); 30 | }, 31 | function (err) { 32 | console.log(err.data); 33 | return cb(err.data); 34 | }) 35 | }, 36 | register: function (formData, callback) { 37 | var cb = callback || angular.noop; 38 | User.save(formData, 39 | function (user) { 40 | $rootScope.currentUser = user; 41 | return cb(); 42 | }, 43 | function (err) { 44 | console.log(err.data) 45 | return cb(err.data); 46 | }) 47 | }, 48 | currentUser: function () { 49 | Session.get(function (user) { 50 | $rootScope.currentUser = user; 51 | }); 52 | }, 53 | authenticate: function () { 54 | Session.get(function (user) { 55 | if (user) { 56 | $rootScope.loggedIn = true; 57 | return true; 58 | } 59 | else { 60 | $rootScope.loggedIn = false; 61 | return false; 62 | } 63 | }); 64 | } 65 | } 66 | }) 67 | 68 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/controllers/cam/draw.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | 3 | .controller('camDrawController', function ($scope, $state, FriendService, SnapService) { 4 | 5 | $scope.friends = {} 6 | $scope.sendFriends = [] 7 | $scope.data = { 8 | availableOptions: [ 9 | { value: '1', name: '1' }, 10 | { value: '2', name: '2' }, 11 | { value: '3', name: '3' }, 12 | { value: '4', name: '4' }, 13 | { value: '5', name: '5' }, 14 | { value: '6', name: '6' }, 15 | { value: '7', name: '7' }, 16 | { value: '8', name: '8' }, 17 | { value: '9', name: '9' }, 18 | { value: '10', name: '10' } 19 | ], 20 | selectedOption: { value: '5', name: '5' } //This sets the default value of the select in the ui 21 | }; 22 | 23 | 24 | FriendService.listFriends(function (friends) { 25 | $scope.friends = friends; 26 | }) 27 | 28 | $scope.conf = { 29 | width: $scope.$parent.snapWidth, 30 | height: $scope.$parent.snapHeight, 31 | imageData: $scope.$parent.snapImage 32 | } 33 | $scope.checked = function (username, checkedval) { 34 | if (checkedval) { 35 | $scope.sendFriends.push(username) 36 | } 37 | else { 38 | if ($scope.sendFriends.indexOf(username) !== -1) 39 | $scope.sendFriends.splice($scope.sendFriends.indexOf(username), 1) 40 | } 41 | } 42 | 43 | $scope.sendSnap = function () { 44 | 45 | $scope.loading = true; 46 | 47 | var c = document.getElementById('snapcan') 48 | var dataURL = c.toDataURL(); 49 | //get friends 50 | //get message 51 | //get time 52 | 53 | sendSnapObj = { 54 | img: dataURL, 55 | friends: $scope.sendFriends, 56 | time: $scope.data.selectedOption.value, 57 | text: $scope.loveMessage 58 | } 59 | 60 | SnapService.sendSnap(sendSnapObj, function (err) { 61 | if (!err) { 62 | $scope.loading = false; 63 | $state.go('main') 64 | } 65 | $scope.errors = err; 66 | }) 67 | } 68 | 69 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/services/Auth.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('RedSnap') 4 | .factory('Auth', function Auth($rootScope, User, Session, $cookieStore) { 5 | $rootScope.currentUser = $cookieStore.get('user') || null; 6 | $cookieStore.remove('user'); 7 | 8 | return { 9 | 10 | login: function (userData, callback) { 11 | var cb = callback || angular.noop; 12 | Session.save({ 13 | username: userData.username, 14 | password: userData.password 15 | }, 16 | function (user) { 17 | $rootScope.curentUser = user 18 | return cb(); 19 | }, 20 | function (err) { 21 | console.log(err.data) 22 | return cb(err.data); 23 | }) 24 | }, 25 | logout: function (callback) { 26 | var cb = callback || angular.noop; 27 | Session.delete(function (res) { 28 | $rootScope.curentUser = null; 29 | return cb(); 30 | }, 31 | function (err) { 32 | console.log(err.data); 33 | return cb(err.data); 34 | }) 35 | }, 36 | register: function (formData, callback) { 37 | var cb = callback || angular.noop; 38 | User.save(formData, 39 | function (user) { 40 | $rootScope.currentUser = user; 41 | return cb(); 42 | }, 43 | function (err) { 44 | console.log(err.data) 45 | return cb(err.data); 46 | }) 47 | }, 48 | currentUser: function () { 49 | Session.get(function (user) { 50 | $rootScope.currentUser = user; 51 | }); 52 | }, 53 | authenticate: function () { 54 | Session.get(function (user) { 55 | if (user) { 56 | $rootScope.loggedIn = true; 57 | return true; 58 | } 59 | else { 60 | $rootScope.loggedIn = false; 61 | return false; 62 | } 63 | }); 64 | } 65 | } 66 | }) 67 | 68 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/controllers/cam/draw.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | 3 | .controller('camDrawController', function ($scope, $state, FriendService, SnapService) { 4 | 5 | $scope.friends = {} 6 | $scope.sendFriends = [] 7 | $scope.data = { 8 | availableOptions: [ 9 | { value: '1', name: '1' }, 10 | { value: '2', name: '2' }, 11 | { value: '3', name: '3' }, 12 | { value: '4', name: '4' }, 13 | { value: '5', name: '5' }, 14 | { value: '6', name: '6' }, 15 | { value: '7', name: '7' }, 16 | { value: '8', name: '8' }, 17 | { value: '9', name: '9' }, 18 | { value: '10', name: '10' } 19 | ], 20 | selectedOption: { value: '5', name: '5' } //This sets the default value of the select in the ui 21 | }; 22 | 23 | 24 | FriendService.listFriends(function (friends) { 25 | $scope.friends = friends; 26 | }) 27 | 28 | $scope.conf = { 29 | width: $scope.$parent.snapWidth, 30 | height: $scope.$parent.snapHeight, 31 | imageData: $scope.$parent.snapImage 32 | } 33 | $scope.checked = function (username, checkedval) { 34 | if (checkedval) { 35 | $scope.sendFriends.push(username) 36 | } 37 | else { 38 | if ($scope.sendFriends.indexOf(username) !== -1) 39 | $scope.sendFriends.splice($scope.sendFriends.indexOf(username), 1) 40 | } 41 | } 42 | 43 | $scope.sendSnap = function () { 44 | 45 | $scope.loading = true; 46 | 47 | var c = document.getElementById('snapcan') 48 | var dataURL = c.toDataURL(); 49 | //get friends 50 | //get message 51 | //get time 52 | 53 | sendSnapObj = { 54 | img: dataURL, 55 | friends: $scope.sendFriends, 56 | time: $scope.data.selectedOption.value, 57 | text: $scope.loveMessage 58 | } 59 | 60 | SnapService.sendSnap(sendSnapObj, function (err) { 61 | if (!err) { 62 | $scope.loading = false; 63 | $state.go('main') 64 | } 65 | $scope.errors = err; 66 | }) 67 | } 68 | 69 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/bin/download.ps1: -------------------------------------------------------------------------------- 1 | $runtimeUrl = $args[0] 2 | $overrideUrl = $args[1] 3 | $current = [string] (Get-Location -PSProvider FileSystem) 4 | $client = New-Object System.Net.WebClient 5 | 6 | function downloadWithRetry { 7 | param([string]$url, [string]$dest, [int]$retry) 8 | Write-Host 9 | Write-Host "Attempt: $retry" 10 | Write-Host 11 | trap { 12 | Write-Host $_.Exception.ToString() 13 | if ($retry -lt 5) { 14 | $retry=$retry+1 15 | Write-Host 16 | Write-Host "Waiting 5 seconds and retrying" 17 | Write-Host 18 | Start-Sleep -s 5 19 | downloadWithRetry $url $dest $retry $client 20 | } 21 | else { 22 | Write-Host "Download failed" 23 | throw "Max number of retries downloading [5] exceeded" 24 | } 25 | } 26 | $client.downloadfile($url, $dest) 27 | } 28 | 29 | function download($url, $dest) { 30 | Write-Host "Downloading $url" 31 | downloadWithRetry $url $dest 1 32 | } 33 | 34 | function copyOnVerify($file, $output) { 35 | Write-Host "Verifying $file" 36 | $verify = Get-AuthenticodeSignature $file 37 | Out-Host -InputObject $verify 38 | if ($verify.Status -ne "Valid") { 39 | throw "Invalid signature for runtime package $file" 40 | } 41 | else { 42 | mv $file $output 43 | } 44 | } 45 | 46 | if ($overrideUrl) { 47 | Write-Host "Using override url: $overrideUrl" 48 | $url = $overrideUrl 49 | } 50 | else { 51 | $url = $runtimeUrl 52 | } 53 | 54 | foreach($singleUrl in $url -split ";") 55 | { 56 | $suffix = Get-Random 57 | $downloaddir = $current + "\sandbox" + $suffix 58 | mkdir $downloaddir 59 | $dest = $downloaddir + "\sandbox.exe" 60 | download $singleUrl $dest 61 | $final = $downloaddir + "\runtime.exe" 62 | copyOnVerify $dest $final 63 | if (Test-Path -LiteralPath $final) 64 | { 65 | cd $downloaddir 66 | if ($host.Version.Major -eq 3) 67 | { 68 | .\runtime.exe -y | Out-Null 69 | .\setup.cmd 70 | } 71 | else 72 | { 73 | Start-Process -FilePath $final -ArgumentList -y -Wait 74 | $cmd = $downloaddir + "\setup.cmd" 75 | Start-Process -FilePath $cmd -Wait 76 | } 77 | } 78 | else 79 | { 80 | throw "Unable to verify package" 81 | } 82 | cd $current 83 | if (Test-Path -LiteralPath $downloaddir) 84 | { 85 | Remove-Item -LiteralPath $downloaddir -Force -Recurse 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/core.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('RedSnap', ['ui.router', 'ui.bootstrap', 'ngCookies', 'ngSanitize', 'ngResource', 'ngAnimate', 'webcam', 'http-auth-interceptor']) 4 | .config(function ($stateProvider, $urlRouterProvider) { 5 | 6 | $urlRouterProvider.otherwise('/'); 7 | 8 | $stateProvider 9 | .state('main', { 10 | url: '/', 11 | templateUrl: '/views/main.html', 12 | controller: 'mainController', 13 | resolve: { 14 | authenticate: function (Auth) { 15 | return Auth.authenticate(); 16 | } 17 | } 18 | }) 19 | .state('cam', { 20 | abstract: true, 21 | url: '/cam', 22 | template: '', 23 | controller: 'camController', 24 | resolve: { 25 | authenticate: function (Auth) { 26 | return Auth.authenticate(); 27 | } 28 | } 29 | }) 30 | .state('cam.view', { 31 | url: '/view', 32 | templateUrl: '/views/cam/view.html', 33 | controller: 'camViewController' 34 | }) 35 | .state('cam.draw', { 36 | url: '/draw', 37 | templateUrl: '/views/cam/draw.html', 38 | controller: 'camDrawController' 39 | }) 40 | .state('friends', { 41 | url: '/friends', 42 | templateUrl: '/views/friends.html', 43 | controller: 'friendsController', 44 | resolve: { 45 | authenticate: function (Auth) { 46 | return Auth.authenticate(); 47 | } 48 | } 49 | }) 50 | .state('login', { 51 | url: '/login', 52 | templateUrl: '/views/login.html', 53 | controller: 'loginController' 54 | }) 55 | .state('logout', { 56 | url: '/logout', 57 | templateUrl: '/views/logout.html', 58 | controller: 'logoutController' 59 | }) 60 | .state('register', { 61 | url: '/register', 62 | templateUrl: '/views/register.html', 63 | controller: 'registerController' 64 | }) 65 | }) 66 | .run(function ($rootScope, $state, $location, Auth) { 67 | $rootScope.$watch('currentUser', function (currentUser) { 68 | if (!$rootScope.currentUser && !$state.includes('login')) { 69 | Auth.currentUser(); 70 | } 71 | }); 72 | //On 401, redirect to login, implements http-auth-interceptor 73 | $rootScope.$on('event:auth-loginRequired', function () { 74 | $rootScope.loggedIn = false; 75 | $location.path('/login') 76 | return false; 77 | }) 78 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/core.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('RedSnap', ['ui.router', 'ui.bootstrap', 'ngCookies', 'ngSanitize', 'ngResource', 'ngAnimate', 'webcam', 'http-auth-interceptor']) 4 | .config(function ($stateProvider, $urlRouterProvider) { 5 | 6 | $urlRouterProvider.otherwise('/'); 7 | 8 | $stateProvider 9 | .state('main', { 10 | url: '/', 11 | templateUrl: '/views/main.html', 12 | controller: 'mainController', 13 | resolve: { 14 | authenticate: function (Auth) { 15 | return Auth.authenticate(); 16 | } 17 | } 18 | }) 19 | .state('cam', { 20 | abstract: true, 21 | url: '/cam', 22 | template: '', 23 | controller: 'camController', 24 | resolve: { 25 | authenticate: function (Auth) { 26 | return Auth.authenticate(); 27 | } 28 | } 29 | }) 30 | .state('cam.view', { 31 | url: '/view', 32 | templateUrl: '/views/cam/view.html', 33 | controller: 'camViewController' 34 | }) 35 | .state('cam.draw', { 36 | url: '/draw', 37 | templateUrl: '/views/cam/draw.html', 38 | controller: 'camDrawController' 39 | }) 40 | .state('friends', { 41 | url: '/friends', 42 | templateUrl: '/views/friends.html', 43 | controller: 'friendsController', 44 | resolve: { 45 | authenticate: function (Auth) { 46 | return Auth.authenticate(); 47 | } 48 | } 49 | }) 50 | .state('login', { 51 | url: '/login', 52 | templateUrl: '/views/login.html', 53 | controller: 'loginController' 54 | }) 55 | .state('logout', { 56 | url: '/logout', 57 | templateUrl: '/views/logout.html', 58 | controller: 'logoutController' 59 | }) 60 | .state('register', { 61 | url: '/register', 62 | templateUrl: '/views/register.html', 63 | controller: 'registerController' 64 | }) 65 | }) 66 | .run(function ($rootScope, $state, $location, Auth) { 67 | $rootScope.$watch('currentUser', function (currentUser) { 68 | if (!$rootScope.currentUser && !$state.includes('login')) { 69 | Auth.currentUser(); 70 | } 71 | }); 72 | //On 401, redirect to login, implements http-auth-interceptor 73 | $rootScope.$on('event:auth-loginRequired', function () { 74 | $rootScope.loggedIn = false; 75 | $location.path('/login') 76 | return false; 77 | }) 78 | }); -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/controllers/main.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | .controller('mainController', function ($scope, $interval, $uibModal, SnapService) { 3 | 4 | $scope.snaps = {}; 5 | $scope.snapData = {} 6 | var time = 0; 7 | 8 | 9 | SnapService.listSnaps(function (snaps) { 10 | $scope.snaps = snaps; 11 | }) 12 | 13 | $scope.open = function (snapRequestData) { 14 | 15 | SnapService.viewSnap(snapRequestData, function (snap) { 16 | $scope.snapData = snap 17 | time = $scope.snapData.time; 18 | 19 | var modalInstance = $uibModal.open({ 20 | animation: $scope.animationsEnabled, 21 | templateUrl: '../../views/snapModal.html', 22 | controller: 'snapModalController', 23 | keyboard: true, 24 | scope: $scope 25 | }) 26 | 27 | SnapService.listSnaps(function (snaps) { 28 | $scope.snaps = snaps; 29 | }) 30 | 31 | modalInstance.result.then(function () { 32 | if (angular.isDefined(promise)) { 33 | $interval.cancel(promise) 34 | } 35 | }, function () { 36 | if (angular.isDefined(promise)) { 37 | $interval.cancel(promise) 38 | } 39 | }); 40 | }) 41 | 42 | } 43 | 44 | var fetcher = $interval(function () { 45 | SnapService.listSnaps(function (snaps) { 46 | $scope.snaps = snaps; 47 | }) 48 | }, 90000) 49 | 50 | $scope.$on('$destroy', function () { 51 | $interval.cancel(fetcher); 52 | }) 53 | 54 | $scope.start = function (modInst) { 55 | promise = $interval(function () { 56 | $scope.snapData.time--; 57 | if ($scope.snapData.time < 1) { 58 | modInst.close(); 59 | } 60 | }, 1000, time) 61 | } 62 | 63 | }) 64 | 65 | angular.module('RedSnap') 66 | .controller('snapModalController', function ($scope, $interval, $timeout, $uibModalInstance) { 67 | 68 | $timeout(function () { //hack to render DOM before controller logic. Will move into directive 69 | var img = new Image; 70 | 71 | var c = document.getElementById('bg-can') 72 | c.width = 640; 73 | c.height = 480; 74 | var ctx = c.getContext('2d'); 75 | img.onload = function () { 76 | ctx.drawImage(img, 0, 0); 77 | } 78 | img.src = $scope.snapData.imgData; 79 | 80 | $scope.start($uibModalInstance); 81 | }, 0) 82 | 83 | 84 | 85 | 86 | }) -------------------------------------------------------------------------------- /RedSnap/RedSnap/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var favicon = require('serve-favicon'); 4 | var logger = require('morgan'); 5 | var cookieParser = require('cookie-parser'); 6 | var bodyParser = require('body-parser'); 7 | var session = require('express-session'); 8 | var RedisStore = require('connect-redis') (session); 9 | 10 | var config = require('./config.js'); 11 | var mongoose = require('mongoose'); 12 | 13 | var client = require('./systems/rediscon.js') 14 | 15 | client.on('connect', function () { 16 | console.log('Connection to Redis Server established'); 17 | }); 18 | 19 | global.appRoot = path.resolve(__dirname); 20 | 21 | var app = express(); 22 | 23 | var passport = require('passport'); 24 | var User = require('./models/User'); 25 | 26 | //var io = require('socket.io').listen(app); 27 | //var socket = require('./controllers/socket'); 28 | 29 | mongoose.connect(config.mongoURL, config.mongoOptions, function (err, res) { 30 | if (err) console.log("error connecting to db " + err) 31 | else console.log('Connection to MongoDB instance established') 32 | }); 33 | 34 | var pass = require('./systems/pass') 35 | 36 | app.use(favicon(__dirname + '/public/images/favicon.ico')); 37 | app.use(logger('dev')); 38 | app.use(bodyParser.json({limit: '2048kb' })); 39 | app.use(bodyParser.urlencoded({ extended: false })); 40 | app.use(session({ 41 | secret: 'McGillCollegeAveXs', 42 | store: new RedisStore({ client: client, ttl: 260 }), 43 | saveUninitialized: false, 44 | resave: false 45 | })) 46 | app.use(cookieParser()); 47 | app.use(require('stylus').middleware(path.join(__dirname, 'public'))); 48 | app.use(express.static(path.join(__dirname, 'public'))); 49 | 50 | app.use(passport.initialize()); 51 | app.use(passport.session()); 52 | 53 | require('./routes.js')(app); 54 | 55 | // catch 404 and forward to error handler 56 | app.use(function (req, res, next) { 57 | var err = new Error('Not Found'); 58 | err.status = 404; 59 | next(err); 60 | }); 61 | 62 | // error handlers 63 | 64 | // development error handler 65 | // will print stacktrace 66 | if (app.get('env') === 'development') { 67 | app.use(function (err, req, res, next) { 68 | res.status(err.status || 500); 69 | res.render('error', { 70 | message: err.message, 71 | error: err 72 | }); 73 | }); 74 | } 75 | 76 | // production error handler 77 | // no stacktraces leaked to user 78 | app.use(function (err, req, res, next) { 79 | res.status(err.status || 500); 80 | res.render('error', { 81 | message: err.message, 82 | error: {} 83 | }); 84 | }); 85 | 86 | //io.sockets.on('connection', socket) 87 | 88 | module.exports = app; 89 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/controllers/main.js: -------------------------------------------------------------------------------- 1 | angular.module('RedSnap') 2 | .controller('mainController', function ($scope, $interval, $uibModal, SnapService) { 3 | 4 | $scope.snaps = {}; 5 | $scope.snapData = {} 6 | var time = 0; 7 | 8 | 9 | SnapService.listSnaps(function (snaps) { 10 | $scope.snaps = snaps; 11 | }) 12 | 13 | $scope.open = function (snapRequestData) { 14 | 15 | SnapService.viewSnap(snapRequestData, function (snap) { 16 | $scope.snapData = snap 17 | time = $scope.snapData.time; 18 | 19 | var modalInstance = $uibModal.open({ 20 | animation: $scope.animationsEnabled, 21 | templateUrl: '../../views/snapModal.html', 22 | controller: 'snapModalController', 23 | keyboard: true, 24 | scope: $scope 25 | }) 26 | 27 | SnapService.listSnaps(function (snaps) { 28 | $scope.snaps = snaps; 29 | }) 30 | 31 | modalInstance.result.then(function () { 32 | if (angular.isDefined(promise)) { 33 | $interval.cancel(promise) 34 | } 35 | }, function () { 36 | if (angular.isDefined(promise)) { 37 | $interval.cancel(promise) 38 | } 39 | }); 40 | }) 41 | 42 | } 43 | 44 | var fetcher = $interval(function () { 45 | SnapService.listSnaps(function (snaps) { 46 | $scope.snaps = snaps; 47 | }) 48 | }, 90000) 49 | 50 | $scope.$on('$destroy', function () { 51 | $interval.cancel(fetcher); 52 | }) 53 | 54 | $scope.start = function (modInst) { 55 | promise = $interval(function () { 56 | $scope.snapData.time--; 57 | if ($scope.snapData.time < 1) { 58 | modInst.close(); 59 | } 60 | }, 1000, time) 61 | } 62 | 63 | }) 64 | 65 | angular.module('RedSnap') 66 | .controller('snapModalController', function ($scope, $interval, $timeout, $uibModalInstance) { 67 | 68 | $timeout(function () { //hack to render DOM before controller logic. Will move into directive 69 | var img = new Image; 70 | 71 | var c = document.getElementById('bg-can') 72 | c.width = 640; 73 | c.height = 480; 74 | var ctx = c.getContext('2d'); 75 | img.onload = function () { 76 | ctx.drawImage(img, 0, 0); 77 | } 78 | img.src = $scope.snapData.imgData; 79 | 80 | $scope.start($uibModalInstance); 81 | }, 0) 82 | 83 | 84 | 85 | 86 | }) -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/stylesheets/style.styl: -------------------------------------------------------------------------------- 1 | body 2 | padding: 50px 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif 4 | a 5 | color: #00B7FF 6 | .navbar-default { 7 | background-color: #cb1c0a; 8 | border-color: #911205; 9 | } 10 | .navbar-default .navbar-brand { 11 | color: #ecf0f1; 12 | } 13 | .navbar-default .navbar-brand:hover, 14 | .navbar-default .navbar-brand:focus { 15 | color: #ffbbbc; 16 | } 17 | .navbar-default .navbar-text { 18 | color: #ecf0f1; 19 | } 20 | .navbar-default .navbar-nav > li > a { 21 | color: #ecf0f1; 22 | } 23 | .navbar-default .navbar-nav > li > a:hover, 24 | .navbar-default .navbar-nav > li > a:focus { 25 | color: #ffbbbc; 26 | } 27 | .navbar-default .navbar-nav > .active > a, 28 | .navbar-default .navbar-nav > .active > a:hover, 29 | .navbar-default .navbar-nav > .active > a:focus { 30 | color: #ffbbbc; 31 | background-color: #911205; 32 | } 33 | .navbar-default .navbar-nav > .open > a, 34 | .navbar-default .navbar-nav > .open > a:hover, 35 | .navbar-default .navbar-nav > .open > a:focus { 36 | color: #ffbbbc; 37 | background-color: #911205; 38 | } 39 | .navbar-default .navbar-toggle { 40 | border-color: #911205; 41 | } 42 | .navbar-default .navbar-toggle:hover, 43 | .navbar-default .navbar-toggle:focus { 44 | background-color: #911205; 45 | } 46 | .navbar-default .navbar-toggle .icon-bar { 47 | background-color: #ecf0f1; 48 | } 49 | .navbar-default .navbar-collapse, 50 | .navbar-default .navbar-form { 51 | border-color: #ecf0f1; 52 | } 53 | .navbar-default .navbar-link { 54 | color: #ecf0f1; 55 | } 56 | .navbar-default .navbar-link:hover { 57 | color: #ffbbbc; 58 | } 59 | 60 | @media (max-width: 767px) { 61 | .navbar-default .navbar-nav .open .dropdown-menu > li > a { 62 | color: #ecf0f1; 63 | } 64 | .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, 65 | .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { 66 | color: #ffbbbc; 67 | } 68 | .navbar-default .navbar-nav .open .dropdown-menu > .active > a, 69 | .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, 70 | .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { 71 | color: #ffbbbc; 72 | background-color: #911205; 73 | } 74 | } 75 | .cam-box 76 | text-align: center 77 | margin-top: 10px 78 | .webcam-live 79 | width: 85% 80 | height: auto 81 | z-index: -1 82 | #snapButton 83 | z-index: 100 84 | position: relative 85 | display: block 86 | margin: -6.5% auto 87 | width: 40% 88 | background: rgba(60, 60, 60, 0.4) 89 | #snapButton:active 90 | background: rgba(255, 100, 100, 0.8) 91 | .form-signin-heading 92 | color: white 93 | #login-well 94 | background-color: #cb1c0a 95 | max-width: 320px; 96 | margin: 20px auto; 97 | border-color: #911205; 98 | #login-text 99 | max-width: 420px; 100 | margin: 10px auto; 101 | #login-title 102 | margin-top: 0 103 | .snap-img 104 | width: 640px 105 | height: 480px 106 | background-image:url('../images/snap.png') 107 | margin: 10px auto 108 | #bg-can 109 | position: absolute 110 | z-index: 1100 111 | .modal-content 112 | min-width: 680px 113 | 114 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 35 | 36 | 37 | 38 | 40 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 74 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | a { 6 | color: #00b7ff; 7 | } 8 | .navbar-default { 9 | background-color: #cb1c0a; 10 | border-color: #911205; 11 | } 12 | .navbar-default .navbar-brand { 13 | color: #ecf0f1; 14 | } 15 | .navbar-default .navbar-brand:hover, 16 | .navbar-default .navbar-brand:focus { 17 | color: #ffbbbc; 18 | } 19 | .navbar-default .navbar-text { 20 | color: #ecf0f1; 21 | } 22 | .navbar-default .navbar-nav > li > a { 23 | color: #ecf0f1; 24 | } 25 | .navbar-default .navbar-nav > li > a:hover, 26 | .navbar-default .navbar-nav > li > a:focus { 27 | color: #ffbbbc; 28 | } 29 | .navbar-default .navbar-nav > .active > a, 30 | .navbar-default .navbar-nav > .active > a:hover, 31 | .navbar-default .navbar-nav > .active > a:focus { 32 | color: #ffbbbc; 33 | background-color: #911205; 34 | } 35 | .navbar-default .navbar-nav > .open > a, 36 | .navbar-default .navbar-nav > .open > a:hover, 37 | .navbar-default .navbar-nav > .open > a:focus { 38 | color: #ffbbbc; 39 | background-color: #911205; 40 | } 41 | .navbar-default .navbar-toggle { 42 | border-color: #911205; 43 | } 44 | .navbar-default .navbar-toggle:hover, 45 | .navbar-default .navbar-toggle:focus { 46 | background-color: #911205; 47 | } 48 | .navbar-default .navbar-toggle .icon-bar { 49 | background-color: #ecf0f1; 50 | } 51 | .navbar-default .navbar-collapse, 52 | .navbar-default .navbar-form { 53 | border-color: #ecf0f1; 54 | } 55 | .navbar-default .navbar-link { 56 | color: #ecf0f1; 57 | } 58 | .navbar-default .navbar-link:hover { 59 | color: #ffbbbc; 60 | } 61 | @media (max-width: 767px) { 62 | .navbar-default .navbar-nav .open .dropdown-menu > li > a { 63 | color: #ecf0f1; 64 | } 65 | .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, 66 | .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { 67 | color: #ffbbbc; 68 | } 69 | .navbar-default .navbar-nav .open .dropdown-menu > .active > a, 70 | .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, 71 | .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { 72 | color: #ffbbbc; 73 | background-color: #911205; 74 | } 75 | } 76 | .cam-box { 77 | text-align: center; 78 | margin-top: 10px; 79 | } 80 | .webcam-live { 81 | width: 85%; 82 | height: auto; 83 | z-index: -1; 84 | } 85 | #snapButton { 86 | z-index: 100; 87 | position: relative; 88 | display: block; 89 | margin: -6.5% auto; 90 | width: 40%; 91 | background: rgba(60,60,60,0.4); 92 | } 93 | #snapButton:active { 94 | background: rgba(255,100,100,0.8); 95 | } 96 | .form-signin-heading { 97 | color: #fff; 98 | } 99 | #login-well { 100 | background-color: #cb1c0a; 101 | max-width: 320px; 102 | margin: 20px auto; 103 | border-color: #911205; 104 | } 105 | #login-text { 106 | max-width: 420px; 107 | margin: 10px auto; 108 | } 109 | #login-title { 110 | margin-top: 0; 111 | } 112 | .snap-img { 113 | width: 640px; 114 | height: 480px; 115 | background-image: url("../images/snap.png"); 116 | margin: 10px auto; 117 | } 118 | #bg-can { 119 | position: absolute; 120 | z-index: 1100; 121 | } 122 | .modal-content { 123 | min-width: 680px; 124 | } 125 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/models/User.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | var Schema = mongoose.Schema; 3 | var crypto = require('crypto'); 4 | 5 | var UserSchema = new Schema({ 6 | username: { 7 | type: String, required: true, unique: true 8 | }, 9 | email: { 10 | type: String, required: true, unique: true 11 | }, 12 | date_joined: { 13 | type: Date, required: true, default: Date 14 | }, 15 | snap_count: { 16 | sent: { type: Number, default: 0 }, 17 | received: { type: Number, default: 0 } 18 | }, 19 | friends: { 20 | requested: [{username: String}], 21 | current: [{username: String}] 22 | }, 23 | hashedPassword: String, 24 | salt: String 25 | 26 | }); 27 | 28 | UserSchema.virtual('password') 29 | .set(function (password) { 30 | this._password = password; 31 | this.salt = this.makeSalt(); 32 | this.hashedPassword = this.encryptPassword(password); 33 | }) 34 | .get(function () { 35 | return this._password; 36 | }); 37 | 38 | 39 | UserSchema 40 | .virtual('user_info') 41 | .get(function () { 42 | return { '_id': this._id, 'username': this.username, 'email': this.email, 'snap_count': this.snap_count, 'friends': this.friends }; 43 | }); 44 | 45 | var validatePresenceOf = function (value) { 46 | return value && value.length; 47 | }; 48 | 49 | UserSchema.path('email').validate(function (email) { 50 | var emailRegex = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/; 51 | return emailRegex.test(email); 52 | }, 'The specified email is invalid.'); 53 | 54 | UserSchema.path('email').validate(function (value, respond) { 55 | mongoose.models["User"].findOne({ email: value }, function (err, user) { 56 | if (err) throw err; 57 | if (user) return respond(false); 58 | respond(true); 59 | }); 60 | }, 'The specified email address is already in use.'); 61 | 62 | UserSchema.path('username').validate(function (value, respond) { 63 | mongoose.models["User"].findOne({ username: value }, function (err, user) { 64 | if (err) throw err; 65 | if (user) return respond(false); 66 | respond(true); 67 | }); 68 | }, 'The specified username is already in use.'); 69 | 70 | UserSchema.pre('save', function (next) { 71 | if (!this.isNew) { 72 | return next(); 73 | } 74 | 75 | if (!validatePresenceOf(this.password)) { 76 | next(new Error('Invalid password')); 77 | } 78 | else { 79 | next(); 80 | } 81 | }); 82 | 83 | 84 | UserSchema.methods = { 85 | 86 | /** 87 | * Authenticate - check if the passwords are the same 88 | */ 89 | 90 | authenticate: function (plainText) { 91 | return this.encryptPassword(plainText) === this.hashedPassword; 92 | }, 93 | 94 | /** 95 | * Make salt 96 | */ 97 | 98 | makeSalt: function () { 99 | return crypto.randomBytes(16).toString('base64'); 100 | }, 101 | 102 | /** 103 | * Encrypt password 104 | */ 105 | 106 | encryptPassword: function (password) { 107 | if (!password || !this.salt) return ''; 108 | var salt = new Buffer(this.salt, 'base64'); 109 | return crypto.pbkdf2Sync(password, salt, 10000, 64).toString('base64'); 110 | } 111 | }; 112 | 113 | mongoose.model('User', UserSchema); 114 | 115 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/routes.js: -------------------------------------------------------------------------------- 1 | var passport = require('passport'); 2 | var auth = require('./systems/auth'); 3 | var nocache = require('./systems/nocache.js'); 4 | 5 | module.exports = function (app) { 6 | // User Routes 7 | var session = require('./controllers/session'); 8 | var users = require('./controllers/user'); 9 | var snap = require('./controllers/snap'); 10 | 11 | app.get('/api/snaps', nocache, auth.ensureAuthenticated, snap.receivesnaps); 12 | app.post('/api/snaps', auth.ensureAuthenticated, snap.sendsnaps); 13 | 14 | app.post('/api/snaps/view', auth.ensureAuthenticated, snap.viewsnap); 15 | 16 | app.get('/api/friends', nocache, auth.ensureAuthenticated, users.friends); 17 | app.post('/api/friends', auth.ensureAuthenticated, users.friend); 18 | app.delete('/api/friends', auth.ensureAuthenticated, users.unfriend); 19 | 20 | app.post('/auth/users', users.register); 21 | 22 | app.get('/auth/session', auth.ensureAuthenticated, session.session); 23 | app.post('/auth/session', session.login); 24 | app.delete('/auth/session', session.logout); 25 | 26 | // Angular Routes 27 | //app.get('/views/main', auth.ensureAuthenticated, session.session, function (req, res) { 28 | // res.send('views/main.html') 29 | //}) 30 | //app.get('/views/*', function (req, res) { 31 | // var requestedView = path.join('./', req.url); 32 | // res.send(requestedView); 33 | //}); 34 | 35 | app.get('/*', function (req, res) { 36 | if (req.user) { 37 | res.cookie('user', JSON.stringify(req.user)); 38 | } 39 | 40 | res.send('index.html'); 41 | }); 42 | 43 | } 44 | 45 | //module.exports = function (app) { 46 | 47 | // app.get('api/account', auth.ensureAuthenticated, function (req, res) { 48 | // if (req.isAuthenticated()) { 49 | // res.json(req.user); 50 | // } 51 | // res.send(401); 52 | // }); 53 | 54 | // app.post('api/account/login', 55 | // passport.authenticate('local', function (req, res) { 56 | // User.find({username: req.body.username}, function (err, user) { 57 | // if (err) res.send(err); 58 | // var identity = { 59 | // id: user._id, 60 | // username: user.username, 61 | // email: user.email, 62 | // friends: user.friends, 63 | // snap_count: user.snap_count 64 | // } 65 | // res.send(identity); 66 | // }) 67 | // })); 68 | 69 | 70 | 71 | // app.post('api/account/register', function (req, res) { 72 | // User.register(new User({ username: req.body.username, email: req.body.email }), req.body.password, function (err) { 73 | // if (err) console.log('error during registration') 74 | // }); 75 | // User.find({ username: req.body.username }, function (err, user) { 76 | // var identity = { 77 | // id: user._id, 78 | // username: user.username, 79 | // email: user.email, 80 | // friends: user.friends, 81 | // snap_count: user.snap_count 82 | // } 83 | // res.send(identity); 84 | // }) 85 | // }); 86 | // app.get('api/account/logout', function (req, res) { 87 | // req.logout(); 88 | // res.status(200); 89 | // }) 90 | // //app.get('/views/*', function (req, res) { 91 | // // var view = path.join('./', req.url); 92 | // // console.log(view) 93 | // // res.sendfile(view) 94 | // //}) 95 | // //app.get('/', function (req, res) { 96 | // // if (req.user) { 97 | // // res.cookie('user', JSON.stringify(user)); 98 | // // } 99 | // // res.sendfile(index.html) 100 | // //}) 101 | //} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### RedSnap 2 | An open-source web-based Snapchat clone. Built with node.js, express.js, angular, mongodb and redis. 3 | 4 | *Historically, privacy was almost implicit, because it was hard to find and gather information. But in the digital world, whether it’s digital cameras or satellites or just what you click on, we need to have more explicit rules—not just for governments but for private companies. —Bill Gates* 5 | 6 | Works in the latest versions of Edge, Firefox and Chrome (use https to enable webcam). Works to some degree on Android Chrome. Please read the [notice] (https://github.com/gaessaki/RedSnap/blob/master/README.md#notice) before trying the site out. As the app was built as an MVP over the weekend, the code is by no means an indicator of best practices. There are many vulnerabilities that I am aware of in the code and I am sure you will find more (Please contribute fixes if you can). DEMO: https://myhack.ca. 7 | 8 | #### Why did I build this? 9 | 10 | My primary intention was to practice my web development skills as I come from a .NET and Android background. The more I got into it however, the more I saw the importance and the need of an open-source alternative to Snapchat. By no means am I anti-Snapchat (I'll still probably use it every day for the time being), but the incentives are evident: 11 | 12 | * As a non-profit open source project, no complicitness in comprimising data to advertisters or the gov't 13 | * Project development not geared towards monetization (e.g. ads, blocking 3rd party clients) 14 | * Clients can be built for any device (Yay Windows Phone! Or perhaps integration with a digital camera, drone, etc.?) 15 | * Users can host private RedSnap servers that only members of their community can join (e.g. family, company, school club) 16 | * Customize your own installation of RedSnap however you want. Change snapping rules, colour schemes, make your own filter, etc. 17 | * An example of a complete node.js/angular project for newbies to learn from 18 | 19 | The node.js app can expose its API and thus iOS, Android, Windows Phone, Raspberry Pi, etc. clients are all possible. Please email me at mansib.rahman@outlook.com if you are interested in contributing. 20 | 21 | ## Notice 22 | 23 | As it stands, RedSnap is WIP and thus I can make no guarantee of security, privacy or functionality. Refrain from submitting personally indentifiable information or any data that you would not like compromised (i.e. personal photos) into the system. **Use at your own risk.** 24 | 25 | ## Installation 26 | 27 | Requires MongoDB and Redis instances. To install, clone the repo and then create a config.js file in the root folder of the application (the one with app.js). Then include the following in the file: 28 | 29 | ``` 30 | module.exports = { 31 | mongoURL : 'mongodb://[host]:[port]/[DB]', 32 | mongoOptions : { 33 | user : '[username]', 34 | pass : '[password]' 35 | }, 36 | redisURL: 'redis://x:[password]@[host]:[port]', 37 | deleteSnaps: true 38 | } 39 | ``` 40 | As you can imagine, the ```deleteSnaps``` option determines whether snaps are deleted. If set to false, The user may review any snaps she or he has received repeatedly. 41 | 42 | ## Program Structure 43 | 44 | The app bootstraps from **app.js** which connects to the databases and enables the API routes. All the routes and middlewares are outlined in **routes.js**, also in the same folders. The meat of the API calls are in the controllers folder in the app root. Users are stored in MongoDB, for which the models resides in the models folder. The systems folder contains misc code that is to be reused throughout the backend (passport bootstrapping, redis connection, cron job to delete snaps, etc.) 45 | 46 | All the client (i.e. browser) content resides in the public folder. If you're familiar with Angular, the structure should be clear enough. All the html files are stored in view. Each html has a corresponding controller in the public/javascripts/controllers folder. The angular app is bootstrapped in **core.js**, which is in the javascripts folder. 47 | 48 | The bin folder is for Azure to start an instance of the app. 49 | 50 | ## Contributors 51 | 52 | * Mostafa Saadat - Tested app functionality throughout the hacking process, made favicon 53 | * Afuad Hossain - Discovered bug in friending functionality during use 54 | * Zack Ohlin - Discovered bug in friending functionality during use 55 | * 'Daft Monk' - Used his [Angular-Passport CRUD demo] (https://github.com/DaftMonk/angular-passport) as the inspiration RedSnap's auth system 56 | 57 | ## License 58 | 59 | [MIT] (https://github.com/gaessaki/RedSnap/blob/master/LICENSE) 60 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/providers/socket.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @license 3 | * angular-socket-io v0.7.0 4 | * (c) 2014 Brian Ford http://briantford.com 5 | * License: MIT 6 | */ 7 | 8 | angular.module('btford.socket-io', []). 9 | provider('socketFactory', function () { 10 | 11 | 'use strict'; 12 | 13 | // when forwarding events, prefix the event name 14 | var defaultPrefix = 'socket:', 15 | ioSocket; 16 | 17 | // expose to provider 18 | this.$get = ['$rootScope', '$timeout', function ($rootScope, $timeout) { 19 | 20 | var asyncAngularify = function (socket, callback) { 21 | return callback ? function () { 22 | var args = arguments; 23 | $timeout(function () { 24 | callback.apply(socket, args); 25 | }, 0); 26 | } : angular.noop; 27 | }; 28 | 29 | return function socketFactory(options) { 30 | options = options || {}; 31 | var socket = options.ioSocket || io.connect(); 32 | var prefix = options.prefix === undefined ? defaultPrefix : options.prefix; 33 | var defaultScope = options.scope || $rootScope; 34 | 35 | var addListener = function (eventName, callback) { 36 | socket.on(eventName, callback.__ng = asyncAngularify(socket, callback)); 37 | }; 38 | 39 | var addOnceListener = function (eventName, callback) { 40 | socket.once(eventName, callback.__ng = asyncAngularify(socket, callback)); 41 | }; 42 | 43 | var wrappedSocket = { 44 | on: addListener, 45 | addListener: addListener, 46 | once: addOnceListener, 47 | 48 | emit: function (eventName, data, callback) { 49 | var lastIndex = arguments.length - 1; 50 | var callback = arguments[lastIndex]; 51 | if (typeof callback == 'function') { 52 | callback = asyncAngularify(socket, callback); 53 | arguments[lastIndex] = callback; 54 | } 55 | return socket.emit.apply(socket, arguments); 56 | }, 57 | 58 | removeListener: function (ev, fn) { 59 | if (fn && fn.__ng) { 60 | arguments[1] = fn.__ng; 61 | } 62 | return socket.removeListener.apply(socket, arguments); 63 | }, 64 | 65 | removeAllListeners: function () { 66 | return socket.removeAllListeners.apply(socket, arguments); 67 | }, 68 | 69 | disconnect: function (close) { 70 | return socket.disconnect(close); 71 | }, 72 | 73 | connect: function () { 74 | return socket.connect(); 75 | }, 76 | 77 | // when socket.on('someEvent', fn (data) { ... }), 78 | // call scope.$broadcast('someEvent', data) 79 | forward: function (events, scope) { 80 | if (events instanceof Array === false) { 81 | events = [events]; 82 | } 83 | if (!scope) { 84 | scope = defaultScope; 85 | } 86 | events.forEach(function (eventName) { 87 | var prefixedEvent = prefix + eventName; 88 | var forwardBroadcast = asyncAngularify(socket, function () { 89 | Array.prototype.unshift.call(arguments, prefixedEvent); 90 | scope.$broadcast.apply(scope, arguments); 91 | }); 92 | scope.$on('$destroy', function () { 93 | socket.removeListener(eventName, forwardBroadcast); 94 | }); 95 | socket.on(eventName, forwardBroadcast); 96 | }); 97 | } 98 | }; 99 | 100 | return wrappedSocket; 101 | }; 102 | }]; 103 | }); 104 | 105 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/providers/socket.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @license 3 | * angular-socket-io v0.7.0 4 | * (c) 2014 Brian Ford http://briantford.com 5 | * License: MIT 6 | */ 7 | 8 | angular.module('btford.socket-io', []). 9 | provider('socketFactory', function () { 10 | 11 | 'use strict'; 12 | 13 | // when forwarding events, prefix the event name 14 | var defaultPrefix = 'socket:', 15 | ioSocket; 16 | 17 | // expose to provider 18 | this.$get = ['$rootScope', '$timeout', function ($rootScope, $timeout) { 19 | 20 | var asyncAngularify = function (socket, callback) { 21 | return callback ? function () { 22 | var args = arguments; 23 | $timeout(function () { 24 | callback.apply(socket, args); 25 | }, 0); 26 | } : angular.noop; 27 | }; 28 | 29 | return function socketFactory(options) { 30 | options = options || {}; 31 | var socket = options.ioSocket || io.connect(); 32 | var prefix = options.prefix === undefined ? defaultPrefix : options.prefix; 33 | var defaultScope = options.scope || $rootScope; 34 | 35 | var addListener = function (eventName, callback) { 36 | socket.on(eventName, callback.__ng = asyncAngularify(socket, callback)); 37 | }; 38 | 39 | var addOnceListener = function (eventName, callback) { 40 | socket.once(eventName, callback.__ng = asyncAngularify(socket, callback)); 41 | }; 42 | 43 | var wrappedSocket = { 44 | on: addListener, 45 | addListener: addListener, 46 | once: addOnceListener, 47 | 48 | emit: function (eventName, data, callback) { 49 | var lastIndex = arguments.length - 1; 50 | var callback = arguments[lastIndex]; 51 | if (typeof callback == 'function') { 52 | callback = asyncAngularify(socket, callback); 53 | arguments[lastIndex] = callback; 54 | } 55 | return socket.emit.apply(socket, arguments); 56 | }, 57 | 58 | removeListener: function (ev, fn) { 59 | if (fn && fn.__ng) { 60 | arguments[1] = fn.__ng; 61 | } 62 | return socket.removeListener.apply(socket, arguments); 63 | }, 64 | 65 | removeAllListeners: function () { 66 | return socket.removeAllListeners.apply(socket, arguments); 67 | }, 68 | 69 | disconnect: function (close) { 70 | return socket.disconnect(close); 71 | }, 72 | 73 | connect: function () { 74 | return socket.connect(); 75 | }, 76 | 77 | // when socket.on('someEvent', fn (data) { ... }), 78 | // call scope.$broadcast('someEvent', data) 79 | forward: function (events, scope) { 80 | if (events instanceof Array === false) { 81 | events = [events]; 82 | } 83 | if (!scope) { 84 | scope = defaultScope; 85 | } 86 | events.forEach(function (eventName) { 87 | var prefixedEvent = prefix + eventName; 88 | var forwardBroadcast = asyncAngularify(socket, function () { 89 | Array.prototype.unshift.call(arguments, prefixedEvent); 90 | scope.$broadcast.apply(scope, arguments); 91 | }); 92 | scope.$on('$destroy', function () { 93 | socket.removeListener(eventName, forwardBroadcast); 94 | }); 95 | socket.on(eventName, forwardBroadcast); 96 | }); 97 | } 98 | }; 99 | 100 | return wrappedSocket; 101 | }; 102 | }]; 103 | }); 104 | 105 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | RedSnap - Open Source Web SnapChat Clone 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 90 |
91 |
92 |
93 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | RedSnap - Open Source Web SnapChat Clone 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 90 |
91 |
92 |
93 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/services/http-auth-interceptor.js: -------------------------------------------------------------------------------- 1 | /*global angular:true, browser:true */ 2 | 3 | /** 4 | * @license HTTP Auth Interceptor Module for AngularJS 5 | * (c) 2012 Witold Szczerba 6 | * License: MIT 7 | */ 8 | (function () { 9 | 'use strict'; 10 | 11 | angular.module('http-auth-interceptor', ['http-auth-interceptor-buffer']) 12 | 13 | .factory('authService', ['$rootScope', 'httpBuffer', function ($rootScope, httpBuffer) { 14 | return { 15 | /** 16 | * Call this function to indicate that authentication was successfull and trigger a 17 | * retry of all deferred requests. 18 | * @param data an optional argument to pass on to $broadcast which may be useful for 19 | * example if you need to pass through details of the user that was logged in 20 | * @param configUpdater an optional transformation function that can modify the 21 | * requests that are retried after having logged in. This can be used for example 22 | * to add an authentication token. It must return the request. 23 | */ 24 | loginConfirmed: function (data, configUpdater) { 25 | var updater = configUpdater || function (config) { return config; }; 26 | $rootScope.$broadcast('event:auth-loginConfirmed', data); 27 | httpBuffer.retryAll(updater); 28 | }, 29 | 30 | /** 31 | * Call this function to indicate that authentication should not proceed. 32 | * All deferred requests will be abandoned or rejected (if reason is provided). 33 | * @param data an optional argument to pass on to $broadcast. 34 | * @param reason if provided, the requests are rejected; abandoned otherwise. 35 | */ 36 | loginCancelled: function (data, reason) { 37 | httpBuffer.rejectAll(reason); 38 | $rootScope.$broadcast('event:auth-loginCancelled', data); 39 | } 40 | }; 41 | }]) 42 | 43 | /** 44 | * $http interceptor. 45 | * On 401 response (without 'ignoreAuthModule' option) stores the request 46 | * and broadcasts 'event:auth-loginRequired'. 47 | * On 403 response (without 'ignoreAuthModule' option) discards the request 48 | * and broadcasts 'event:auth-forbidden'. 49 | */ 50 | .config(['$httpProvider', function ($httpProvider) { 51 | $httpProvider.interceptors.push(['$rootScope', '$q', 'httpBuffer', function ($rootScope, $q, httpBuffer) { 52 | return { 53 | responseError: function (rejection) { 54 | var config = rejection.config || {}; 55 | if (!config.ignoreAuthModule) { 56 | switch (rejection.status) { 57 | case 401: 58 | var deferred = $q.defer(); 59 | httpBuffer.append(config, deferred); 60 | $rootScope.$broadcast('event:auth-loginRequired', rejection); 61 | return deferred.promise; 62 | case 403: 63 | $rootScope.$broadcast('event:auth-forbidden', rejection); 64 | break; 65 | } 66 | } 67 | // otherwise, default behaviour 68 | return $q.reject(rejection); 69 | } 70 | }; 71 | }]); 72 | }]); 73 | 74 | /** 75 | * Private module, a utility, required internally by 'http-auth-interceptor'. 76 | */ 77 | angular.module('http-auth-interceptor-buffer', []) 78 | 79 | .factory('httpBuffer', ['$injector', function ($injector) { 80 | /** Holds all the requests, so they can be re-requested in future. */ 81 | var buffer = []; 82 | 83 | /** Service initialized later because of circular dependency problem. */ 84 | var $http; 85 | 86 | function retryHttpRequest(config, deferred) { 87 | function successCallback(response) { 88 | deferred.resolve(response); 89 | } 90 | function errorCallback(response) { 91 | deferred.reject(response); 92 | } 93 | $http = $http || $injector.get('$http'); 94 | $http(config).then(successCallback, errorCallback); 95 | } 96 | 97 | return { 98 | /** 99 | * Appends HTTP request configuration object with deferred response attached to buffer. 100 | */ 101 | append: function (config, deferred) { 102 | buffer.push({ 103 | config: config, 104 | deferred: deferred 105 | }); 106 | }, 107 | 108 | /** 109 | * Abandon or reject (if reason provided) all the buffered requests. 110 | */ 111 | rejectAll: function (reason) { 112 | if (reason) { 113 | for (var i = 0; i < buffer.length; ++i) { 114 | buffer[i].deferred.reject(reason); 115 | } 116 | } 117 | buffer = []; 118 | }, 119 | 120 | /** 121 | * Retries all the buffered requests clears the buffer. 122 | */ 123 | retryAll: function (updater) { 124 | for (var i = 0; i < buffer.length; ++i) { 125 | retryHttpRequest(updater(buffer[i].config), buffer[i].deferred); 126 | } 127 | buffer = []; 128 | } 129 | }; 130 | }]); 131 | })(); 132 | 133 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/services/http-auth-interceptor.js: -------------------------------------------------------------------------------- 1 | /*global angular:true, browser:true */ 2 | 3 | /** 4 | * @license HTTP Auth Interceptor Module for AngularJS 5 | * (c) 2012 Witold Szczerba 6 | * License: MIT 7 | */ 8 | (function () { 9 | 'use strict'; 10 | 11 | angular.module('http-auth-interceptor', ['http-auth-interceptor-buffer']) 12 | 13 | .factory('authService', ['$rootScope', 'httpBuffer', function ($rootScope, httpBuffer) { 14 | return { 15 | /** 16 | * Call this function to indicate that authentication was successfull and trigger a 17 | * retry of all deferred requests. 18 | * @param data an optional argument to pass on to $broadcast which may be useful for 19 | * example if you need to pass through details of the user that was logged in 20 | * @param configUpdater an optional transformation function that can modify the 21 | * requests that are retried after having logged in. This can be used for example 22 | * to add an authentication token. It must return the request. 23 | */ 24 | loginConfirmed: function (data, configUpdater) { 25 | var updater = configUpdater || function (config) { return config; }; 26 | $rootScope.$broadcast('event:auth-loginConfirmed', data); 27 | httpBuffer.retryAll(updater); 28 | }, 29 | 30 | /** 31 | * Call this function to indicate that authentication should not proceed. 32 | * All deferred requests will be abandoned or rejected (if reason is provided). 33 | * @param data an optional argument to pass on to $broadcast. 34 | * @param reason if provided, the requests are rejected; abandoned otherwise. 35 | */ 36 | loginCancelled: function (data, reason) { 37 | httpBuffer.rejectAll(reason); 38 | $rootScope.$broadcast('event:auth-loginCancelled', data); 39 | } 40 | }; 41 | }]) 42 | 43 | /** 44 | * $http interceptor. 45 | * On 401 response (without 'ignoreAuthModule' option) stores the request 46 | * and broadcasts 'event:auth-loginRequired'. 47 | * On 403 response (without 'ignoreAuthModule' option) discards the request 48 | * and broadcasts 'event:auth-forbidden'. 49 | */ 50 | .config(['$httpProvider', function ($httpProvider) { 51 | $httpProvider.interceptors.push(['$rootScope', '$q', 'httpBuffer', function ($rootScope, $q, httpBuffer) { 52 | return { 53 | responseError: function (rejection) { 54 | var config = rejection.config || {}; 55 | if (!config.ignoreAuthModule) { 56 | switch (rejection.status) { 57 | case 401: 58 | var deferred = $q.defer(); 59 | httpBuffer.append(config, deferred); 60 | $rootScope.$broadcast('event:auth-loginRequired', rejection); 61 | return deferred.promise; 62 | case 403: 63 | $rootScope.$broadcast('event:auth-forbidden', rejection); 64 | break; 65 | } 66 | } 67 | // otherwise, default behaviour 68 | return $q.reject(rejection); 69 | } 70 | }; 71 | }]); 72 | }]); 73 | 74 | /** 75 | * Private module, a utility, required internally by 'http-auth-interceptor'. 76 | */ 77 | angular.module('http-auth-interceptor-buffer', []) 78 | 79 | .factory('httpBuffer', ['$injector', function ($injector) { 80 | /** Holds all the requests, so they can be re-requested in future. */ 81 | var buffer = []; 82 | 83 | /** Service initialized later because of circular dependency problem. */ 84 | var $http; 85 | 86 | function retryHttpRequest(config, deferred) { 87 | function successCallback(response) { 88 | deferred.resolve(response); 89 | } 90 | function errorCallback(response) { 91 | deferred.reject(response); 92 | } 93 | $http = $http || $injector.get('$http'); 94 | $http(config).then(successCallback, errorCallback); 95 | } 96 | 97 | return { 98 | /** 99 | * Appends HTTP request configuration object with deferred response attached to buffer. 100 | */ 101 | append: function (config, deferred) { 102 | buffer.push({ 103 | config: config, 104 | deferred: deferred 105 | }); 106 | }, 107 | 108 | /** 109 | * Abandon or reject (if reason provided) all the buffered requests. 110 | */ 111 | rejectAll: function (reason) { 112 | if (reason) { 113 | for (var i = 0; i < buffer.length; ++i) { 114 | buffer[i].deferred.reject(reason); 115 | } 116 | } 117 | buffer = []; 118 | }, 119 | 120 | /** 121 | * Retries all the buffered requests clears the buffer. 122 | */ 123 | retryAll: function (updater) { 124 | for (var i = 0; i < buffer.length; ++i) { 125 | retryHttpRequest(updater(buffer[i].config), buffer[i].deferred); 126 | } 127 | buffer = []; 128 | } 129 | }; 130 | }]); 131 | })(); 132 | 133 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/controllers/user.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'), 2 | User = mongoose.model('User'), 3 | passport = require('passport'); 4 | 5 | exports.register = function (req, res, next) { 6 | console.log("registering user") 7 | var registrant = new User({ 8 | username : req.body.username, 9 | password : req.body.password, 10 | email : req.body.email 11 | }); 12 | 13 | registrant.save(function (err) { 14 | if (err) { 15 | console.log(err) 16 | return res.json(err) 17 | } 18 | }) 19 | 20 | req.logIn(registrant, function (err) { 21 | if (err) return next(err); 22 | return res.json(registrant.user_info); 23 | }) 24 | } 25 | 26 | exports.friends = function (req, res, next) { 27 | console.log('listing friends for ' + req.user.username) 28 | User.findOne({ 'username': req.user.username }, 'friends', function (err, user) { 29 | console.log(user.friends); 30 | return res.json(user.friends); 31 | }) 32 | } 33 | 34 | exports.friend = function (req, res, next) { 35 | if (!req.body.friend) { 36 | console.log("No friend added"); 37 | return res.send().status(400).end(); 38 | } 39 | console.log(req.user.username + ' is attempting to friend ' + req.body.friend) 40 | if (req.user.username == req.body.friend) { 41 | console.log("Can't friend yourself!"); 42 | return res.send().status(400).end(); 43 | } 44 | else { 45 | User.findOne({ 'username' : req.body.friend }, function (err, user) { 46 | if (err || !user) { 47 | console.log(err) 48 | return res.send(err).status(400).end();//user presumably not found 49 | } 50 | var isCurrFriend = user.user_info.friends.current.map(function (e) { return e.username; }).indexOf(req.user.username); 51 | var isReqFriend = user.user_info.friends.requested.map(function (e) { return e.username; }).indexOf(req.user.username); 52 | if (isCurrFriend != -1) { 53 | console.log(req.user.username + ' is already friends with ' + req.body.friend) 54 | return res.send(req.user.username + ' is already friends with ' + req.body.friend).status(400).end() 55 | //return res.json(req.user.username + ' is already friends with ' + req.body.friend) 56 | } 57 | else { 58 | User.findOne({ 'username' : req.user.username }, function (err, currUser) { 59 | if (err) { 60 | console.log(err) 61 | return res.send(err).status(400).end(); //user presumably not found, but how would that even be possible? 62 | } 63 | var isUserFriendIndex = currUser.user_info.friends.requested.map(function (e) { return e.username; }).indexOf(user.username); //currUser.user_info.friends.requested.indexOf(user.username); 64 | console.log(isUserFriendIndex) 65 | if (isUserFriendIndex != -1) { //is there an existing request from interested party? If so, both users should be friends now 66 | 67 | User.findOneAndUpdate({ 'username' : req.user.username }, { 68 | $push: { 69 | 'friends.current' : { 70 | '_id': user._id, 71 | 'username': user.username 72 | } 73 | }, 74 | $pull: { 75 | 'friends.requested' : { 76 | 'username': user.username 77 | } 78 | } 79 | 80 | }, function (err, us) { 81 | if (err) console.log(err); 82 | }) 83 | User.findOneAndUpdate({ 'username' : req.body.friend }, { 84 | $push: { 85 | 'friends.current' : { 86 | '_id': currUser._id, 87 | 'username': currUser.username 88 | } 89 | } 90 | }, function (err, us) { 91 | if (err) console.log(err); 92 | return res.send().status(200).end(); 93 | }) 94 | } 95 | else if (isReqFriend) { //Did the user send a request to the friend in the past? If not, then send it now 96 | user.user_info.friends.requested.push({ _id: req.user._id, username: req.user.username }); 97 | User.findOneAndUpdate({ 'username' : req.body.friend }, user, function (err, us) { 98 | if (err) console.log(err); 99 | }) 100 | return res.send().status(200).end(); 101 | } 102 | else { 103 | return res.send().status(404).end(); 104 | } 105 | }) 106 | } 107 | }) 108 | } 109 | 110 | } 111 | //check if friend exists 112 | //check if friend already 113 | //check if user has already send request 114 | //if so then confirm that both are now friends, remove requested friend for both users and add current for both 115 | //if not then set user as requested friend for target 116 | 117 | exports.unfriend = function (req, res, next) { 118 | console.log(req.user.username + " is trying to unfriend " + req.query.friend) 119 | User.findOneAndUpdate({ 'username' : req.query.friend }, { 120 | $pull : { 121 | 'friends.current' : { 122 | 'username': req.user.username 123 | } 124 | } 125 | }, function (err, user) { 126 | if (err) { 127 | console.log(err); 128 | return res.send(err); 129 | } 130 | }) 131 | User.findOneAndUpdate({ 'username' : req.user.username }, { 132 | $pull : { 133 | 'friends.current' : { 134 | 'username': req.query.friend 135 | } 136 | } 137 | }, function (err, user) { 138 | if (err) { 139 | console.log(err); 140 | return res.send(err); 141 | } 142 | else { 143 | } 144 | }) 145 | return res.send().status(200).end() 146 | } 147 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/public/javascripts/directives/webcam.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Webcam Directive 3 | * 4 | * (c) Jonas Hartmann http://jonashartmann.github.io/webcam-directive 5 | * License: MIT 6 | * 7 | * @version: 3.1.0 8 | */ 9 | 'use strict'; 10 | 11 | (function () { 12 | // GetUserMedia is not yet supported by all browsers 13 | // Until then, we need to handle the vendor prefixes 14 | navigator.getMedia = (navigator.getUserMedia || 15 | navigator.webkitGetUserMedia || 16 | navigator.mozGetUserMedia || 17 | navigator.msGetUserMedia); 18 | 19 | // Checks if getUserMedia is available on the client browser 20 | window.hasUserMedia = function hasUserMedia() { 21 | return navigator.getMedia ? true : false; 22 | }; 23 | })(); 24 | 25 | angular.module('webcam', []) 26 | .directive('webcam', function () { 27 | return { 28 | template: '
', 29 | restrict: 'E', 30 | replace: true, 31 | transclude: true, 32 | scope: 33 | { 34 | onError: '&', 35 | onStream: '&', 36 | onStreaming: '&', 37 | placeholder: '=', 38 | config: '=channel' 39 | }, 40 | link: function postLink($scope, element) { 41 | var videoElem = null, 42 | videoStream = null, 43 | placeholder = null; 44 | 45 | $scope.config = $scope.config || {}; 46 | 47 | var _removeDOMElement = function _removeDOMElement(DOMel) { 48 | if (DOMel) { 49 | angular.element(DOMel).remove(); 50 | } 51 | }; 52 | 53 | var onDestroy = function onDestroy() { 54 | if (!!videoStream) { 55 | var checker = typeof videoStream.getVideoTracks === 'function'; 56 | if (videoStream.getVideoTracks && checker) { 57 | // get video track to call stop in it 58 | // videoStream.stop() is deprecated and may be removed in the 59 | // near future 60 | // ENSURE THIS IS CHECKED FIRST BEFORE THE FALLBACK 61 | // videoStream.stop() 62 | var tracks = videoStream.getVideoTracks(); 63 | if (tracks && tracks[0] && tracks[0].stop) { 64 | tracks[0].stop(); 65 | } 66 | } else if (videoStream.stop) { 67 | // deprecated, may be removed in the near future 68 | videoStream.stop(); 69 | } 70 | } 71 | if (!!videoElem) { 72 | delete videoElem.src; 73 | } 74 | }; 75 | 76 | // called when camera stream is loaded 77 | var onSuccess = function onSuccess(stream) { 78 | videoStream = stream; 79 | 80 | // Firefox supports a src object 81 | if (navigator.mozGetUserMedia) { 82 | videoElem.mozSrcObject = stream; 83 | } else { 84 | var vendorURL = window.URL || window.webkitURL; 85 | videoElem.src = vendorURL.createObjectURL(stream); 86 | } 87 | 88 | /* Start playing the video to show the stream from the webcam */ 89 | videoElem.play(); 90 | $scope.config.video = videoElem; 91 | 92 | /* Call custom callback */ 93 | if ($scope.onStream) { 94 | $scope.onStream({ stream: stream }); 95 | } 96 | }; 97 | 98 | // called when any error happens 99 | var onFailure = function onFailure(err) { 100 | _removeDOMElement(placeholder); 101 | if (console && console.log) { 102 | console.log('The following error occured: ', err); 103 | } 104 | 105 | /* Call custom callback */ 106 | if ($scope.onError) { 107 | $scope.onError({ err: err }); 108 | } 109 | 110 | return; 111 | }; 112 | 113 | var startWebcam = function startWebcam() { 114 | videoElem = document.createElement('video'); 115 | videoElem.setAttribute('class', 'webcam-live'); 116 | videoElem.setAttribute('autoplay', ''); 117 | element.append(videoElem); 118 | 119 | if ($scope.placeholder) { 120 | placeholder = document.createElement('img'); 121 | placeholder.setAttribute('class', 'webcam-loader'); 122 | placeholder.src = $scope.placeholder; 123 | element.append(placeholder); 124 | } 125 | 126 | // Default variables 127 | var isStreaming = false, 128 | width = element.width = $scope.config.videoWidth || 320, 129 | height = element.height = 0; 130 | 131 | // Check the availability of getUserMedia across supported browsers 132 | if (!window.hasUserMedia()) { 133 | onFailure({ code: -1, msg: 'Browser does not support getUserMedia.' }); 134 | return; 135 | } 136 | 137 | var mediaConstraint = { video: true, audio: false }; 138 | navigator.getMedia(mediaConstraint, onSuccess, onFailure); 139 | 140 | /* Start streaming the webcam data when the video element can play 141 | * It will do it only once 142 | */ 143 | videoElem.addEventListener('canplay', function () { 144 | if (!isStreaming) { 145 | var scale = width / videoElem.videoWidth; 146 | height = (videoElem.videoHeight * scale) || $scope.config.videoHeight; 147 | videoElem.setAttribute('width', width); 148 | videoElem.setAttribute('height', height); 149 | isStreaming = true; 150 | 151 | $scope.config.video = videoElem; 152 | 153 | _removeDOMElement(placeholder); 154 | 155 | /* Call custom callback */ 156 | if ($scope.onStreaming) { 157 | $scope.onStreaming(); 158 | } 159 | } 160 | }, false); 161 | }; 162 | 163 | var stopWebcam = function stopWebcam() { 164 | onDestroy(); 165 | videoElem.remove(); 166 | }; 167 | 168 | $scope.$on('$destroy', onDestroy); 169 | $scope.$on('START_WEBCAM', startWebcam); 170 | $scope.$on('STOP_WEBCAM', stopWebcam); 171 | 172 | startWebcam(); 173 | 174 | } 175 | }; 176 | }); 177 | 178 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/obj/Release/Package/PackageTmp/public/javascripts/directives/webcam.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Webcam Directive 3 | * 4 | * (c) Jonas Hartmann http://jonashartmann.github.io/webcam-directive 5 | * License: MIT 6 | * 7 | * @version: 3.1.0 8 | */ 9 | 'use strict'; 10 | 11 | (function () { 12 | // GetUserMedia is not yet supported by all browsers 13 | // Until then, we need to handle the vendor prefixes 14 | navigator.getMedia = (navigator.getUserMedia || 15 | navigator.webkitGetUserMedia || 16 | navigator.mozGetUserMedia || 17 | navigator.msGetUserMedia); 18 | 19 | // Checks if getUserMedia is available on the client browser 20 | window.hasUserMedia = function hasUserMedia() { 21 | return navigator.getMedia ? true : false; 22 | }; 23 | })(); 24 | 25 | angular.module('webcam', []) 26 | .directive('webcam', function () { 27 | return { 28 | template: '
', 29 | restrict: 'E', 30 | replace: true, 31 | transclude: true, 32 | scope: 33 | { 34 | onError: '&', 35 | onStream: '&', 36 | onStreaming: '&', 37 | placeholder: '=', 38 | config: '=channel' 39 | }, 40 | link: function postLink($scope, element) { 41 | var videoElem = null, 42 | videoStream = null, 43 | placeholder = null; 44 | 45 | $scope.config = $scope.config || {}; 46 | 47 | var _removeDOMElement = function _removeDOMElement(DOMel) { 48 | if (DOMel) { 49 | angular.element(DOMel).remove(); 50 | } 51 | }; 52 | 53 | var onDestroy = function onDestroy() { 54 | if (!!videoStream) { 55 | var checker = typeof videoStream.getVideoTracks === 'function'; 56 | if (videoStream.getVideoTracks && checker) { 57 | // get video track to call stop in it 58 | // videoStream.stop() is deprecated and may be removed in the 59 | // near future 60 | // ENSURE THIS IS CHECKED FIRST BEFORE THE FALLBACK 61 | // videoStream.stop() 62 | var tracks = videoStream.getVideoTracks(); 63 | if (tracks && tracks[0] && tracks[0].stop) { 64 | tracks[0].stop(); 65 | } 66 | } else if (videoStream.stop) { 67 | // deprecated, may be removed in the near future 68 | videoStream.stop(); 69 | } 70 | } 71 | if (!!videoElem) { 72 | delete videoElem.src; 73 | } 74 | }; 75 | 76 | // called when camera stream is loaded 77 | var onSuccess = function onSuccess(stream) { 78 | videoStream = stream; 79 | 80 | // Firefox supports a src object 81 | if (navigator.mozGetUserMedia) { 82 | videoElem.mozSrcObject = stream; 83 | } else { 84 | var vendorURL = window.URL || window.webkitURL; 85 | videoElem.src = vendorURL.createObjectURL(stream); 86 | } 87 | 88 | /* Start playing the video to show the stream from the webcam */ 89 | videoElem.play(); 90 | $scope.config.video = videoElem; 91 | 92 | /* Call custom callback */ 93 | if ($scope.onStream) { 94 | $scope.onStream({ stream: stream }); 95 | } 96 | }; 97 | 98 | // called when any error happens 99 | var onFailure = function onFailure(err) { 100 | _removeDOMElement(placeholder); 101 | if (console && console.log) { 102 | console.log('The following error occured: ', err); 103 | } 104 | 105 | /* Call custom callback */ 106 | if ($scope.onError) { 107 | $scope.onError({ err: err }); 108 | } 109 | 110 | return; 111 | }; 112 | 113 | var startWebcam = function startWebcam() { 114 | videoElem = document.createElement('video'); 115 | videoElem.setAttribute('class', 'webcam-live'); 116 | videoElem.setAttribute('autoplay', ''); 117 | element.append(videoElem); 118 | 119 | if ($scope.placeholder) { 120 | placeholder = document.createElement('img'); 121 | placeholder.setAttribute('class', 'webcam-loader'); 122 | placeholder.src = $scope.placeholder; 123 | element.append(placeholder); 124 | } 125 | 126 | // Default variables 127 | var isStreaming = false, 128 | width = element.width = $scope.config.videoWidth || 320, 129 | height = element.height = 0; 130 | 131 | // Check the availability of getUserMedia across supported browsers 132 | if (!window.hasUserMedia()) { 133 | onFailure({ code: -1, msg: 'Browser does not support getUserMedia.' }); 134 | return; 135 | } 136 | 137 | var mediaConstraint = { video: true, audio: false }; 138 | navigator.getMedia(mediaConstraint, onSuccess, onFailure); 139 | 140 | /* Start streaming the webcam data when the video element can play 141 | * It will do it only once 142 | */ 143 | videoElem.addEventListener('canplay', function () { 144 | if (!isStreaming) { 145 | var scale = width / videoElem.videoWidth; 146 | height = (videoElem.videoHeight * scale) || $scope.config.videoHeight; 147 | videoElem.setAttribute('width', width); 148 | videoElem.setAttribute('height', height); 149 | isStreaming = true; 150 | 151 | $scope.config.video = videoElem; 152 | 153 | _removeDOMElement(placeholder); 154 | 155 | /* Call custom callback */ 156 | if ($scope.onStreaming) { 157 | $scope.onStreaming(); 158 | } 159 | } 160 | }, false); 161 | }; 162 | 163 | var stopWebcam = function stopWebcam() { 164 | onDestroy(); 165 | videoElem.remove(); 166 | }; 167 | 168 | $scope.$on('$destroy', onDestroy); 169 | $scope.$on('START_WEBCAM', startWebcam); 170 | $scope.$on('STOP_WEBCAM', stopWebcam); 171 | 172 | startWebcam(); 173 | 174 | } 175 | }; 176 | }); 177 | 178 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/RedSnap.njsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | RedSnap 7 | RedSnap 8 | 9 | 10 | 11 | Debug 12 | 2.0 13 | da47b884-6324-463e-bf38-692f7f7a3f32 14 | . 15 | bin\www 16 | 17 | 18 | . 19 | . 20 | v4.0 21 | {3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD} 22 | ShowAllFiles 23 | 1337 24 | true 25 | 26 | 27 | true 28 | 29 | 30 | true 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | False 117 | True 118 | 0 119 | / 120 | http://localhost:48022/ 121 | False 122 | True 123 | http://localhost:1337 124 | False 125 | 126 | 127 | 128 | 129 | 130 | 131 | CurrentPage 132 | True 133 | False 134 | False 135 | False 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | False 145 | False 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /RedSnap/RedSnap/controllers/snap.js: -------------------------------------------------------------------------------- 1 | var redis = require('redis'); 2 | var async = require('async'); 3 | var mkdirp = require('mkdirp'); 4 | var crypto = require('crypto'); 5 | var uuid = require('node-uuid'); 6 | const fs = require('fs'); 7 | 8 | var conf = require('../config') 9 | 10 | var mongoose = require('mongoose'), 11 | User = mongoose.model('User'); 12 | var client = require('../systems/rediscon.js'); 13 | 14 | exports.receivesnaps = function (req, res, next) { 15 | var snaps = [] 16 | client.lrange(req.user.username, 0, -1, function (err, obj) { 17 | if (err) { 18 | console.log(err) 19 | return res.status(400).send().end(); 20 | } 21 | else { 22 | console.log(obj) 23 | async.each(obj, function (item, cb) { 24 | client.hgetall(item, function (err, snapHash) { 25 | if (err) { 26 | console.log(err); 27 | } 28 | snaps.push(snap = { 29 | id: item, 30 | sender: snapHash.sender 31 | }); 32 | console.log(item); 33 | cb(); 34 | }) 35 | }, function () { 36 | if (snaps) { 37 | console.log(200) 38 | return res.status(200).send(snaps); 39 | } 40 | }) 41 | } 42 | }) 43 | } 44 | 45 | exports.viewsnap = function (req, res, next) { 46 | var snapResData = {} 47 | var dataURIIdentifier = "data:image/png;base64,"; 48 | client.hgetall(req.body.snapInfo.id, function (err, snapHash) { 49 | if (err) { 50 | console.log(err); 51 | return res.status(400).end(); 52 | } 53 | else { 54 | fs.readFile(snapHash.imgloc, 'base64', function (err, data) { 55 | if (err) console.log(err); 56 | else { 57 | var imgdata = dataURIIdentifier.concat(data); 58 | snapResData = { 59 | id: req.body.snapInfo.id, 60 | sender: snapHash.sender, 61 | time: snapHash.time, 62 | msg: snapHash.msg, 63 | imgData: imgdata 64 | } 65 | 66 | if (conf.deleteSnaps) { 67 | var friendsArr = snapHash.friends.split(','); //regex may be better for this 68 | var ind = friendsArr.indexOf(req.user.username); 69 | var friendsStr = ""; 70 | console.log(friendsArr) 71 | friendsArr.splice(ind, 1) 72 | 73 | //Check if there are more friends that need to see snap, if not, then queue snap for deletion 74 | if (friendsArr != ['']) { 75 | for (i = 0; i < friendsArr.length; i++) { 76 | friendsStr = friendsStr.concat(req.user.username + ','); 77 | } 78 | } 79 | else { 80 | client.lpush('deletion', req.body.snapInfo.id) 81 | } 82 | 83 | client.hset(req.body.snapInfo.id, 'friends', friendsStr); 84 | client.lrem(req.user.username, 1, req.body.snapInfo.id); 85 | } 86 | return res.status(200).json(snapResData); 87 | } 88 | }) 89 | } 90 | }) 91 | } 92 | 93 | exports.sendsnaps = function (req, res, next) { 94 | if (req.body.snap.friends.length < 1) { 95 | console.log("No friends selected!"); 96 | return res.status(400).send("No friends were selected!"); 97 | } 98 | 99 | var md5sum = crypto.createHash('md5').update(req.user.username + new Date().toString()).digest('hex'); 100 | var dirPath = './snapStorage/' 101 | + md5sum.substring(0, 2) + '/' 102 | + md5sum.substring(2, 4) + '/' 103 | + md5sum.substring(4, 7) + '/' 104 | + md5sum.substring(7, 14) + '/'; 105 | 106 | mkdirp(dirPath, function (err) { 107 | if (err) { 108 | console.log(err + 'ho') 109 | return res.status(400).send(err).end(); 110 | } 111 | else { 112 | var b64imgData = req.body.snap.img.replace(/^data:image\/png;base64,/, ""); 113 | fs.writeFile(dirPath + md5sum.substring(14, 32) + '.txt', b64imgData, 'base64', function (err) { 114 | if (err) { 115 | console.log(err + 'eh') 116 | return res.status(400).send(err).end(); 117 | } 118 | else { 119 | incrSnapSentCount(req.user.username, function (err) { 120 | if (err) { 121 | console.log(err + 'ah') 122 | return res.status(400).send(err).end() 123 | } 124 | else { 125 | var snap_id = uuid.v4(); 126 | var friendArrayString = ""; //I know this is bad... forgive me 127 | async.each(req.body.snap.friends, function (friend, cb) { 128 | console.log(friend) 129 | incrSnapRecCount(friend, function (err) { 130 | if (err) { 131 | return cb(err) 132 | } 133 | else { 134 | client.lpush(friend, snap_id); 135 | friendArrayString = friendArrayString.concat(friend + ',') 136 | cb(); 137 | } 138 | }) 139 | }, function (err) { 140 | if (err) { 141 | console.log(err) 142 | return res.status(400).send(err).end(); 143 | } 144 | if (!req.body.snap.text) { 145 | req.body.snap.text = ""; 146 | } 147 | client.hmset(snap_id, { 148 | "sender": req.user.username, 149 | "imgloc": dirPath + md5sum.substring(14, 32) + '.txt', 150 | "timestamp": new Date(), 151 | "time": req.body.snap.time, 152 | "msg": req.body.snap.text, 153 | "friends": friendArrayString 154 | }); 155 | return res.status(200).send().end(); 156 | }); 157 | /*for (i = 0; i < req.body.snap.friends.length; i++) { 158 | var friend = req.body.snap.friends[i]; 159 | 160 | incrSnapRecCount(friend, function (err) { 161 | if (err) { 162 | console.log(err + 'eh '); 163 | return res.status(400).send(err).end(); 164 | } 165 | else { 166 | client.lpush(friend, snap_id); 167 | friendArrayString += ',' + friend; 168 | } 169 | }) 170 | }*/ 171 | 172 | } 173 | }) 174 | } 175 | }) 176 | } 177 | }) 178 | } 179 | 180 | var incrSnapSentCount = function (name, cb) { 181 | User.findOneAndUpdate({ username: name }, { 182 | $inc : { 183 | 'snap_count.sent' : 1 184 | } 185 | }, function (err, re) { 186 | if (err) { 187 | return cb(err + 'wo'); 188 | } 189 | else { 190 | return cb(); 191 | } 192 | }) 193 | } 194 | var incrSnapRecCount = function (name, cb) { 195 | User.findOneAndUpdate({ username: name }, { 196 | $inc : { 197 | 'snap_count.received' : 1 198 | } 199 | }, function (err, re) { 200 | if (err) { 201 | return cb(err + 'wa'); 202 | } 203 | else { 204 | return cb(); 205 | } 206 | }) 207 | } 208 | 209 | /* for (k = 0; k < obj.length; k++) { 210 | 211 | client.hgetall(obj[k], function (err, snapHash) { 212 | console.log(k) 213 | if (err) { 214 | console.log(err); 215 | return (err, null); 216 | } 217 | else { 218 | snaps.push(snap = { 219 | id: obj[k], 220 | sender: snapHash.sender 221 | }); 222 | } 223 | console.log(obj[k]); 224 | //snaps[i].sender = snapHash.sender; 225 | }) 226 | } */ 227 | --------------------------------------------------------------------------------