Database now stores hashes of recently used IP's for all users. They are retained for seven days AFTER their LAST use.

This commit is contained in:
rainbow napkin 2024-12-23 15:17:07 -05:00
parent 6b0a73e1c8
commit 6e785dc211
6 changed files with 112 additions and 12 deletions

View file

@ -14,6 +14,10 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
//Built-In Imports
const crypto = require('crypto');
//NPM Imports
const {mongoose} = require('mongoose');
@ -115,6 +119,22 @@ const userSchema = new mongoose.Schema({
enum: emoteModel.typeEnum,
default: emoteModel.typeEnum[0]
}
}],
recentIPs: [{
ipHash: {
type: mongoose.SchemaTypes.String,
required: true
},
firstLog: {
type: mongoose.SchemaTypes.Date,
required: true,
default: new Date()
},
lastLog: {
type: mongoose.SchemaTypes.Date,
required: true,
default: new Date()
}
}]
});
@ -143,7 +163,9 @@ userSchema.pre('save', async function (next){
this.flair = flairDB._id;
}
//If rank was changed
if(this.isModified("rank")){
//force a full log-out
await this.killAllSessions("Your site-wide rank has changed. Sign-in required.");
}
@ -302,6 +324,30 @@ userSchema.statics.getUserList = async function(fullList = false){
return userList;
}
userSchema.statics.processAgedIPRecords = async function(){
//Pull full userlist
const users = await this.find({});
//for every user
users.forEach((userDB) => {
//For every recent ip within the user
userDB.recentIPs.forEach((record, recordI) => {
//Check how long it's been since we've last seen the IP
const daysSinceLastUse = ((new Date() - record.lastLog) / (1000 * 60 * 60 * 24)).toFixed(1);
//If it's been more than a week
if(daysSinceLastUse >= 7){
//Splice out the IP record
userDB.recentIPs.splice(recordI, 1);
//No reason to wait on this since we're done with this user
userDB.save();
}
});
});
}
//methods
userSchema.methods.checkPass = function(pass){
return hashUtil.comparePassword(pass, this.pass);
@ -328,9 +374,7 @@ userSchema.methods.getAuthenticatedSessions = async function(){
}
});
resolve(returnArr);
});
});
@ -412,6 +456,49 @@ userSchema.methods.deleteEmote = async function(name){
}
}
userSchema.methods.tattooIPRecord = async function(ip){
//Create hash
const hashObj = crypto.createHash('md5');
//add IP to the hash
hashObj.update(ip);
//Store the IP hash as a string
const ipHash = hashObj.digest('hex');
//Look for a pre-existing entry for this ipHash
const foundIndex = this.recentIPs.findIndex(checkHash);
//If there is no entry
if(foundIndex == -1){
//create record object
const record = {
ipHash: ipHash,
firstLog: new Date(),
lastLog: new Date()
};
//Pop it into place
this.recentIPs.push(record);
//Save the user doc
await this.save();
//Otherwise, if we already have a record for this IP
}else{
//Update the last logged date for the found record
this.recentIPs[foundIndex].lastLog = new Date();
//Save the user doc
await this.save();
}
//Look for matching ip record
function checkHash(ipRecord){
//return matching records
return ipRecord.ipHash == ipHash;
}
}
//note: if you gotta call this from a request authenticated by it's user, make sure to kill that session first!
userSchema.methods.killAllSessions = async function(reason = "A full log-out from all devices was requested for your account."){
//get authenticated sessions