I have a web ftp portal that was created a few years ago by a developer that is no longer around. The code for the website is written in Node.js. Inside of app.js is the following code:
var validUsers = [{
name:'x',
user:'907c78ef73998eafc2680e5fdd4798a8eef0881a',
pass:'95489cf3039eb2f5938e3daa954d04276bbf90e7',
dir:''
},{
name:'y',
user:'b26e5ebda152e81099ec78be2f9c191ee25e1cd6',
pass:'e3725873ae302e3f12eb97b02feb7457de9706c2',
dir:'y'
},{
name:'y2',
user:'3182b54d9f4d08641b5a9a0fb33f74df5d76b222',
pass:'916b2e1941c9e23610f8bd3462cdb19f55b5c631',
dir:'y2'
},{
name:'y3',
user:'38aa53de31c04bcfae9163cc23b7963ed9cf90f7',
pass:'7a98cf84c2c61a30f6c4e3984c0cad2eb29f5d6f',
dir:'y3'
},{
name:'y4',
user:'51e822c50cc62cdbdb850a439ea75b6d45ac487b',
pass:'da6a77293ddcdc7047dd461a94c88c8377753265',
dir:'y4'
},{
name:'y5',
user:'14ad0aca26e00f615990946181ee3405c6ede0f1',
pass:'4eb4e0e1ea0f04422b5bc6031ee37c8dc971236d',
dir:'y5'
},{
name:'y6',
user:'4ec9bdb28c5da0f9813e9eed55a0f1dc6217a305',
pass:'e72bd0bbd37423bb0c9b9edfb9ce94446161c511',
dir:'y6'
},{
name:'y7',
user:'f4603bd4ae9e4aa2a11d903d0b178b37a57b1bac',
pass:'8a6a67f235738c4b2e4f88d4608bdcf0bbc49f51',
dir:'y7'
},{
name:'Guest',
user:'35675e68f4b5af7b995d9205ad0fc43842f16450',
pass:'370bb444ef91a3999b1c36af97e166f18848e7b7',
dir:'Guest'
},{
name:'y8',
user:'d8f51fbf5e13e9f2637a8d5c4bd1ab251bd61c30',
pass:'1a047e6dd554ffdd67524916820a8fa23acd2c6e',
dir:'y8'
}];
The x and y1-8 are substitutions for the actual client names and corresponding directories. Example being the 'Guest' name and directory. My question is, the user and pass are hash values from crypto. Yet they result in specific usernames and passwords. If I wanted to reset a username or password, or add another. How would I figure out the corresponding hash value to add to the code based on the username/password strings I want to add.
Any input would be very helpful.
EDIT:
The rest of the FTP code:
app.get('/ftp/', function(req, res){
var pageName = 'File Transfer Portal';
var rNav = '',
sNav = '',
cNav = '',
imNav = '',
title = 'companyNameOmitted: '+pageName,
bodyClass = 'top ftp',
keywords = 'keywordsOmitted',
description = 'descriptionOmiited',
url = '/ftp/';
res.render('ftp', {
title: title,
bodyClass: bodyClass,
keywords: keywords,
description: description,
url: siteRoot+url,
pageEmail: 'mailto:?subject='+escape(title)+'&body='+escape(description)+'%0A'+siteRoot+url,
eUrl:escape(siteRoot+url),
eTitle:escape(title),
eDescription:escape(description),
rNav:rNav,
sNav:sNav,
cNav:cNav,
imNav:imNav});
//console.log(uniqId()+':'+pageName);
});
app.post('/ftp/upload', function(req, res){
//console.log(req.files);
var SID = req.cookies.SID;
var sessionUser = (users[SID]) ? users[SID] : false;
if (!!sessionUser){
_.each(req.files,function (file) {
console.log(new Date(curTime()).toGMTString()+' | Recieved '+file.name+' ('+file.size+' bytes) from '+sessionUser.name);
var newPath = __dirname + '/complete/'+_.where(validUsers,{user:sessionUser.user})[0].dir+'/'+file.name;
fs.rename(file.path,newPath,function(err) {
if (err) throw err;
else {
res.redirect('back');
if (sessionUser.name != 'adminOmitted') {
var htmlString = '<b>'+sessionUser.name+'</b> has uploaded a file <b>'+file.name+'</b>.<br /><br />View it on the File Transfer Portal.';
var transport = nodemailer.createTransport("SMTP",{
host: "hostname.com", // hostname
secureConnection: true, // use SSL
port: 465, // port for secure SMTP
auth: {
user: "user#host.com",
pass: "pass"
}
});
transport.sendMail({
sender:'sender#host.com',
to:'receiver#host.com',
subject:'File Upload: '+sessionUser.name+' uploaded '+file.name,
html: htmlString
},function(err) {
if (err) console.log(err);
else console.log('Notification Sent: S&A File Upload: '+sessionUser.name+' uploaded '+file.name);
});
}
}
});
And the login code...
app.get('/ftp/d/:hash/:filename', function(req, res){
var SID = req.cookies.SID;
var ip = req.ip;
//console.log(ip);
var sessionUser = (users[SID]) ? ((users[SID].md5==req.params.hash)&&(users[SID].ip==ip)) ? users[SID] : false : false;
if (sessionUser) {
var realpath = __dirname +'/complete/'+_.where(validUsers,{user:sessionUser.user})[0].dir+'/'+req.params.filename.replace('>','/');
console.log(new Date(curTime()).toGMTString()+' | Sending '+realpath.substr(realpath.indexOf('complete')+9)+' to '+sessionUser.name);
res.download(realpath,realpath.substr(realpath.lastIndexOf('/')+1),function(err){
if (err) {
res.redirect(302,'/ftp/');
throw (err);
}
});
} else {
console.log(new Date(curTime()).toGMTString()+' | Download request failed authorization for '+req.params.filename);
console.log(new Date(curTime()).toGMTString()+' | Hash: '+req.params.hash);
console.log(new Date(curTime()).toGMTString()+' | SID: '+req.cookies.SID);
res.redirect(302,'/ftp/');
}
});
sio.sockets.on('connection', function (socket) {
var SID = socket.handshake.SID;
if (!users[SID]) register(SID,socket.handshake.address.address);
//console.log(users);
socket.on('login',function(data) {
var thisUser = _.where(validUsers,{user:data.u,pass:data.p})[0];
if (_.isEmpty(thisUser)) {
if (!!users[SID].ip) {
console.log(new Date(curTime()).toGMTString()+' | '+users[SID].ip+' has failed logging in.');
console.log(new Date(curTime()).toGMTString()+' | '+'U:'+data.u);
console.log(new Date(curTime()).toGMTString()+' | '+'P:'+data.p);
}
socket.emit('login',{complete:false,name:false});
} else {
console.log(new Date(curTime()).toGMTString()+' | '+thisUser.name+' has logged in.');
users[SID].name = thisUser.name;
users[SID].user = thisUser.user;
socket.emit('login',{complete:true,name:thisUser.name});
}
});
And the disconnect function, the only code between the login and the disconnect functions are a move file and a delete file function which I doubt are of any use.
//console.log(users);
socket.on('disconnect',function() {
setTimeout(function() {
if (!!users[SID]) {
if (curTime()-users[SID].lastTap>30000)
unregister(SID);
else console.log('Not removing; connection still active. ('+users[SID].name+')');
} else (unregister(SID));
},30000);
});
});
and finally, the crypto functions:
function getMD5(string) {
return crypto.
createHash('md5').
update(string).
digest("hex");
}
function getSHA1(string) {
return crypto.
createHash('sha1').
update(string).
digest("hex");
}
I know the formatting isn't perfect, I've tried to keep it as neat as possible, I think that's all of the relevant functions. I doubt the .jade file for the FTP Portal would be of any use.
You can't.
The usernames and passwords have been put through an asymmetric encryption (ie MD5). This was likely done to protect the user's personal information if the server is hacked.
You're still missing the part of the code that handles the authentication and sets the session cookie.
If you can find the code that handles the auth and you know the username beforehand you could re-hash it to cross-reference the username to the entries list.
Otherwise, your only option is to crack the usernames/passwords which can be difficult/impossible depending on their complexity.
Good luck...
Related
iam using mail-listener2 to download files from an gmail account
it works and I can see the files on the mailListener.on("mail",) event but it looks like
files r not save on the attachments folder
on the file event the file.path is undefined so I am guessing it dit not saved...
why I can't see the files?
why there is a .on("attachment") event id i can see the files on "mail" event?
i only want to process png files, is there any filter i can use?
this is my code...
thanks
import path from "path";
var MailListener = require("mail-listener2");
export class InvoiceFileLisetner {
private readonly hostName: string = 'imap.gmail.com'
private readonly userName: string = 'username';
private readonly password: string = 'password';
private readonly port: number;
public Listen() {
var mailListener = new MailListener({
username: this.userName,
password: this.password,
host: this.hostName,
port: 993, // imap port
tls: true,
connTimeout: 10000, // Default by node-imap
authTimeout: 5000, // Default by node-imap,
debug: console.log, // Or your custom function with only one incoming argument. Default: null
tlsOptions: { rejectUnauthorized: false },
mailbox: "INBOX", // mailbox to monitor
searchFilter: ["UNSEEN"], // the search filter being used after an IDLE notification has been retrieved
markSeen: true, // all fetched email willbe marked as seen and not fetched next time
fetchUnreadOnStart: true, // use it only if you want to get all unread email on lib start. Default is `false`,
mailParserOptions: { streamAttachments: true }, // options to be passed to mailParser lib.
attachments: true, // download attachments as they are encountered to the project directory
attachmentOptions: { directory: path.join(__dirname, '\\attachments/') }
});
mailListener.start(); // start listening
mailListener.on("server:connected", function () {
console.log("imapConnected");
});
mailListener.on("server:disconnected", function () {
console.log("imapDisconnected");
});
mailListener.on("error", function (err) {
console.log(err);
});
mailListener.on("mail", function (mail, seqno, attributes) {
if (mail.attachments != undefined) {
let accountName = mail.subject;
let invoiceFile = null;
for (let index = 0; index < mail.attachments.length; index++) {
if (mail.attachments[index].contentType == 'application/vnd.ms-excel') {
}
}
}
// mail processing code goes here
});
mailListener.on("attachment", function (attachment) {
console.log(attachment.path);
});
}
}
I have an Azure Functionapp that processes some data and pushes that data into an Azure servicebus topic.
I require sessions to be enabled on my servicebus topic subscription. I cannot seem to find a way to set the session id when using the javascript functionapp API.
Here is a modified extract from my function app:
module.exports = function (context, streamInput) {
context.bindings.outputSbMsg = [];
context.bindings.logMessage = [];
function push(response) {
let message = {
body: CrowdSourceDatum.encode(response).finish()
, customProperties: {
protoType: manifest.Type
, version: manifest.Version
, id: functionId
, rootType: manifest.RootType
}
, brokerProperties: {
SessionId: "1"
}
context.bindings.outputSbMsg.push(message);
}
.......... some magic happens here.
push(crowdSourceDatum);
context.done();
}
But the sessionId does not seem to get set at all. Any idea on how its possible to enable this?
I tested sessionid on my function, I can set the session id property of a message and view it in Service Bus explorer. Here is my sample code.
var connectionString = 'servicebus_connectionstring';
var serviceBusService = azure.createServiceBusService(connectionString);
var message = {
body: '',
customProperties:
{
messagenumber: 0
},
brokerProperties:
{
SessionId: "1"
}
};
message.body= 'This is Message #101';
serviceBusService.sendTopicMessage('testtopic', message, function(error)
{
if (error)
{
console.log(error);
}
});
Here is the test result.
Please make sure you have enabled the portioning and sessions when you created the topic and the subscription.
I am using google's API for node.js
https://www.npmjs.com/package/googleapis
I am trying to get an array of all channels which belong to the person
who logged into my website with his google account.
I am using this scope for this matter:
''https://www.googleapis.com/auth/youtube.readonly'
Now here is part of my code:
app.get("/oauthcallback", function(req, res) {
//google redirected us back in here with random token
var code = req.query.code;
oauth2Client.getToken(code, function(err, tokens) { //let's check if the query code is valid.
if (err) { //invalid query code.
console.log(err);
res.send(err);
return;
}
//google now verified that the login was correct.
googleAccountVerified(tokens, res); //now decide what to do with it
});
});
function googleAccountVerified(tokens, res){ //successfully verified.
//user was verified by google, continue.
oauth2Client.setCredentials(tokens); //save tokens to an object
//now ask google for the user's details
//with the verified tokens you got.
youtube.channels.list({
forUsername: true,
part: "snippet",
auth: oauth2Client
}, function (err, response) {
if(err) {
res.send("Something went wrong, can't get your google info");
return;
}
console.log(response.items[0].snippet);
res.send("test");
});
}
Now, in this console.log:
console.log(response.items[0].snippet);
I am getting the same info, no matter what account I am using to log into my website:
{ title: 'True',
description: '',
publishedAt: '2005-10-14T10:09:11.000Z',
thumbnails:
{ default: { url: 'https://i.ytimg.com/i/G9p-zLTq1mO1KAwzN2h0YQ/1.jpg?v=51448e08' },
medium: { url: 'https://i.ytimg.com/i/G9p-zLTq1mO1KAwzN2h0YQ/mq1.jpg?v=51448e08' },
high: { url: 'https://i.ytimg.com/i/G9p-zLTq1mO1KAwzN2h0YQ/hq1.jpg?v=51448e08' } },
localized: { title: 'True', description: '' } }
if I do console.log(response) which is the entire response
I get:
{ kind: 'youtube#channelListResponse',
etag: '"m2yskBQFythfE4irbTIeOgYYfBU/ch97FwhvtkdYcbQGBeya1XtFqyQ"',
pageInfo: { totalResults: 1, resultsPerPage: 5 },
items:
[ { kind: 'youtube#channel',
etag: '"m2yskBQFythfE4irbTIeOgYYfBU/bBTQeJyetWCB7vBdSCu-7VLgZug"',
id: 'UCG9p-zLTq1mO1KAwzN2h0YQ',
snippet: [Object] } ] }
So, two problems here:
1) How do I get an array of owned channels by the logged user,
inside the array I need objects which will represent each channel and basic info like channel name, profile pic.
2) why am I getting the info of some random youtube channel called "True"
Not sure about question one but for question two you get the information for the channel called true because you are asking for it. forUsername: true
I would hope that once you correct this the response may contain more than one channel if the username has more than one.
Just a follow up to the question about basic info.
You dont use Youtube API to get an account's profile information. Instead, try Retrieve Profile Information with G+:
To retrieve profile information for a user, use the people.get API method. To get profile information for the currently authorized user, use the userId value of me.
JavaScript example:
// This sample assumes a client object has been created.
// To learn more about creating a client, check out the starter:
// https://developers.google.com/+/quickstart/javascript
gapi.client.load('plus','v1', function(){
var request = gapi.client.plus.people.get({
'userId': 'me'
});
request.execute(function(resp) {
console.log('Retrieved profile for:' + resp.displayName);
});
});
Google Sign-in for Websites also enables Getting profile information:
After you have signed in a user with Google using the default scopes, you can access the user's Google ID, name, profile URL, and email address.
To retrieve profile information for a user, use the getBasicProfile() method. For example:
if (auth2.isSignedIn.get()) {
var profile = auth2.currentUser.get().getBasicProfile();
console.log('ID: ' + profile.getId());
console.log('Full Name: ' + profile.getName());
console.log('Given Name: ' + profile.getGivenName());
console.log('Family Name: ' + profile.getFamilyName());
console.log('Image URL: ' + profile.getImageUrl());
console.log('Email: ' + profile.getEmail());
}
Im actually trying to build up a complete chat with Sails.js websockets but im facing some troubles.
I succeed to send and get new messages when a new client connect to the chat but i would new client to get the older messages (like the 20 last messages sent in the chat).
Message.js (Model)
module.exports = {
attributes: {
name : { type: 'string' },
message : { type: 'string' }
}
};
MessageController.js (Controller)
module.exports = {
new: function(req, res) {
var data = {
name: req.param('name'),
message: req.param('message'),
};
Message.create(data).exec(function created(err, message){
Message.publishCreate({id: message.id, name: message.name, message: message.message});
});
},
subscribe: function(req, res) {
Message.watch(req);
}
};
I had an idea about using the "find" function on my Model but not really conclusive.
I hope im not missing something big about Sails possibilities !
Need your help :) Thanks !
Message.find({sort: 'createdAt ASC'}).exec(function(err, results) {
//results is an array of messages
});
http://sailsjs.org/documentation/concepts/models-and-orm/query-language
I added this code to my subscribe function but i don't receive anything on my client side listening on('message')
/* Get the last 5 messages */
Message.find({sort: 'createdAt DESC'}).limit(5).exec(function(err, messages) {
for (var i = 0; i < messages.length; i++) {
sails.sockets.broadcast(req.socket, 'message', messages[i]);
}
});
I need to test a protractor test case in which a user signs up, receives an email, goes to the link provided in the email and fills up his/her details in activation signup form.
The problem is how can I get the redeem token from the email. My email has a link to the activation page which has the auth token like following:
http://127.0.0.1:3000/#/signup/redeem/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJlOTRhYzY3MC1kYTNlLTQyYTUtODVkZS02NDU4ZjVmZGMwYjAiLCJzdWIiOiJ0ZXN0QGNvZWYuY28iLCJpYXQiOjE0Mjc0OTM5MDMsImV4cCI6MTQyODA5ODcwM30.
But how do I fetch that token so that I can build the url or how can I click that button in my email so that I can complete the flow ? I am using mailcatcher to simulate email.
This is something I've solved recently. Hope the solution would also apply for your use-case.
Prerequisites:
mail-listener2 package
understanding of the concept of promises
Step by step instructions:
Install mail-listener2:
npm install mail-listener2 --save-dev
In your protractor config initialize Mail Listener and make it available globally:
onPrepare: function () {
var MailListener = require("mail-listener2");
// here goes your email connection configuration
var mailListener = new MailListener({
username: "imap-username",
password: "imap-password",
host: "imap-host",
port: 993, // imap port
tls: true,
tlsOptions: { rejectUnauthorized: false },
mailbox: "INBOX", // mailbox to monitor
searchFilter: ["UNSEEN", "FLAGGED"], // the search filter being used after an IDLE notification has been retrieved
markSeen: true, // all fetched email willbe marked as seen and not fetched next time
fetchUnreadOnStart: true, // use it only if you want to get all unread email on lib start. Default is `false`,
mailParserOptions: {streamAttachments: true}, // options to be passed to mailParser lib.
attachments: true, // download attachments as they are encountered to the project directory
attachmentOptions: { directory: "attachments/" } // specify a download directory for attachments
});
mailListener.start();
mailListener.on("server:connected", function(){
console.log("Mail listener initialized");
});
global.mailListener = mailListener;
}),
onCleanUp: function () {
mailListener.stop();
},
Create a helper getLastEmail() function which would wait for an email to be retrieved:
function getLastEmail() {
var deferred = protractor.promise.defer();
console.log("Waiting for an email...");
mailListener.on("mail", function(mail){
deferred.fulfill(mail);
});
return deferred.promise;
};
Example test case:
describe("Sample test case", function () {
beforeEach(function () {
browser.get("/#login");
browser.waitForAngular();
});
it("should login with a registration code sent to an email", function () {
element(by.id("username")).sendKeys("MyUserName");
element(by.id("password")).sendKeys("MyPassword");
element(by.id("loginButton")).click();
browser.controlFlow().await(getLastEmail()).then(function (email) {
expect(email.subject).toEqual("New Registration Code");
expect(email.headers.to).toEqual("myemail#email.com");
// extract registration code from the email message
var pattern = /Registration code is: (\w+)/g;
var regCode = pattern.exec(email.text)[1];
console.log(regCode);
});
});
});
The solution I implemented was using mailcatcher API, if you scroll down a bit you'll find the following about the API:
A fairly RESTful URL schema means you can download a list of messages
in JSON from /messages, each message's metadata with
/messages/:id.json, and then the pertinent parts with
/messages/:id.html and /messages/:id.plain for the default HTML and
plain text version, /messages/:id/:cid for individual attachments by
CID, or the whole message with /messages/:id.source.
So we first fetched the whole json response, parse it and fetch the latest email id:
// Returns the last email id
function(emails, user) {
var email, recipient;
for(var i = emails.length - 1; i >= 0; i--) {
email = emails[i];
for(var j = 0; j < email.recipients.length ; j++) {
recipient = email.recipients[j];
if(recipient == "<"+user+">") {
return email.id;
}
}
}
};
using that email id we can get the body of the email by hitting /messages/:id.plain(of course there are more variants like fetching the email source code or email rendered html, we only needed the message) then we can just parse the body to fetch what we want, following is the code:
browser.driver.get(mailcatcherUrl+"/messages");
browser.driver.findElement(by.tagName('body')).getText().then(function(response) {
var emails, lastEmailId, partialTokens ;
emails = JSON.parse(response);
lastEmailId = getLastEmailId(emails, user);
browser.driver.get(mailcatcherUrl+"/messages/"+lastEmailId+".plain");
browser.driver.findElement(by.tagName('body')).getText().then(function(lastEmail) {
// use latestEmail to get what you want.
});
});
And Cheers!
I had to do the same thing but the mail testing server we were using did not have imap support.
So in case anyone runs into the same issue, I achieved a similar solution as alecxe using mailpop3 npm library.
The thing with the pop3 client, however, was that it doesn't act as a listener so we had to define a helper function that would connect, login and fetch the latest email when we needed to test the latest email.
Something like this:
function getLastEmail() {
var deferred = protractor.promise.defer();
var POP3Client = require("mailpop3");
var client = new POP3Client(port, host, {
tlserrs: false,
enabletls: true,
debug: false
});
client.on("connect", function() {
console.log("CONNECT success");
client.login(username, password);
});
client.on("login", function(status, rawdata) {
if (status) {
console.log("LOGIN/PASS success");
client.retr(1);
} else {
console.log("LOGIN/PASS failed");
client.quit();
}
});
client.on("retr", function(status, msgnumber, data, rawdata) {
if (status === true) {
console.log("RETR success for msgnumber " + msgnumber);
deferred.fulfill(data);
} else {
console.log("RETR failed for msgnumber " + msgnumber);
}
client.quit();
});
return deferred.promise;
}