is session based authentication safe for a chatting application - node.js

I am creating a chat application using next js, node js, express js, and MongoDB. I used the next-auth for authentication. i am using google authentication. I am getting the session object by using the getSession() hook. from this session object, I get the user id which is the same id in the database. I use this "user-id" to post or get information from the database.
my question: is this a safe way because I am not sending any jwt token to verify users from the backend? as you can see I am not sending jwt token.
my concern: if I send or get data like this then anybody can access the data if the know the user-id.
import React, { useEffect, useState } from 'react';
import Link from 'next/link';
import axios from 'axios';
import { getSession } from 'next-auth/react';
import Modal from '../../components/popupchat/modal';
const PopupChat = ({ data }) => {
const [chatList, setChatList] = useState([]);
useEffect(() => {
const getChatList = async () => {
const res = await axios.get(
`${process.env.NEXT_PUBLIC_API_URL}api/chat/admin/${data.user.id}`
);
setChatList(res.data);
};
getChatList();
}, []);
return (
<>
<Modal data={data} />
<div className="overflow-x-auto relative">
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" className="py-3 px-6">
Chat Name
</th>
<th scope="col" className="py-3 px-6">
Chat Title
</th>
<th scope="col" className="py-3 px-6">
Created AT
</th>
<th scope="col" className="py-3 px-6">
Open
</th>
</tr>
</thead>
{chatList &&
chatList.map((singleChat, index) => {
return (
<tbody key={index}>
<tr className="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
<td className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{singleChat.chatName}
</td>
<td className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{singleChat.chatTitle}
</td>
<td className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{singleChat.createdAt}
</td>
<td className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
<Link href={`/popupchat/${singleChat._id}`}>Open</Link>
</td>
</tr>
</tbody>
);
})}
</table>
</div>
</>
);
};
export default PopupChat;
export async function getServerSideProps({ req }) {
const session = await getSession({ req });
if (!session) {
return {
redirect: {
destination: '/login',
permanent: false,
},
};
}
return {
props: {
data: session,
},
};
}

It's not safe at all. "Security by obscurity" is not security, it's an illusion of making something somehow secure. You should always properly secure access to your backend resources. Authenticate users, then establish sessions or provide the frontend client with an access token.
You can include the user ID in the path to your backend endpoint, but the request should contain some credentials (session, access token, even a password) so that the backend can authorize the request. The backend must be able to tell if the caller is authorized to access that user's information. Just knowing the user ID is not enough.

Related

Express.js - Posted data not rendering until refresh the page

I am send and fetch data from MySql Database with Express.js and Sequelize.js. All my code works correctly. My problem is, posted data not rendering on the Handlebars template until refresh the page. I also tried res.render method after SaveSettings method but don't worked. I want to render updated data after redirect.
Solved
You're missing return before settings.update(). Without it, the SaveSettings promise resolves before the update has completed - #Phil
function SaveSettings(Model, values) {
return Model.findByPk(1).then((settings) => {
if (!settings) {
return Model.create(values).catch((e) => console.log(e));
} else {
return settings.update(values).catch((e) => console.log(e));
}
});
}
Routes
router.get("/admin", csrf, isAuth, controller.getGeneral);
router.post("/admin", isAuth, controller.postGeneral);
Controllers
exports.getGeneral = (req, res) => {
Models.General.findByPk(1).then((result) => {
return res.render("dashboard/index", {
title: "General Settings",
data: result,
});
});
};
exports.postGeneral = (req, res) => {
SaveSettings(Models.General, req.body)
.then(() => res.redirect("/admin"));
};
SaveSettings Method
function SaveSettings(Model, values) {
return Model.findByPk(1).then((settings) => {
if (!settings) {
return Model.create(values).catch((e) => console.log(e));
} else {
settings.update(values).catch((e) => console.log(e));
}
});
}
Frontend
<form action="" method="post" class="table-responsive">
<input type="hidden" name="_csrf" value="{{csrfToken}}" />
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-success">Save</button>
</div>
<table class="table table-striped table-sm mt-3">
<thead>
<tr>
<th scope="col">Slot</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody>
<tr>
<td class="align-middle">Name</td>
<td class="align-middle">
<input
name="name"
class="form-control"
type="text"
value="{{data.name}}"
/>
</td>
</tr>
<tr>
<td class="align-middle">Description</td>
<td class="align-middle">
<input
name="description"
class="form-control"
type="text"
value="{{data.description}}"
/>
</td>
</tr>
<tr>
<td class="align-middle">Email</td>
<td class="align-middle">
<input
name="email_address"
class="form-control"
type="email"
value="{{data.email_address}}"
/>
</td>
</tr>
</tbody>
</table>
</form>

angular makes post request of a reactive form automatically

I am trying to develop crud using mean stack. When making HTTP requests, angular works fine, but I only want angular to make post request when the submit button for the reactive form is pressed, but it makes both get and post request to the nodejs/express server automatically. is there any option to make the post only when the form submit button is triggered? Thanks a lot.
pdt: I know is making both requests because I am using morgan in nodejs server.
empleados.component.html
<form [formGroup]="nuevoEmpleado" (submit)="addEmpleado()">
<label>
Nombre:
<input type="text" formControlName="nombre">
</label>
<label>
Apellido:
<input type="text" formControlName="apellido">
</label>
<label>
Cargo:
<input type="text" formControlName="cargo">
</label>
<button type="submit" class="btn btn-primary">Agregar Empleado</button>
</form>
<!--tabla lista de empleados -->
<table class="table table-dark">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Nombre</th>
<th scope="col">Apellido</th>
<th scope="col">Cargo</th>
<th scope="col">acciones</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let empleado of listaEmpleados; let i=index">
<th scope="row">{{ i+1 }}</th>
<td>{{ empleado.nombre }}</td>
<td>{{ empleado.apellido }}</td>
<td>{{ empleado.cargo }}</td>
<td>Eliminar</td>
</tr>
</tbody>
</table>
empleados.components.ts
import { Component, OnInit } from '#angular/core';
import { EmpleadosService } from './empleados.service';
import { FormControl , FormGroup } from '#angular/forms';
import { empleado } from '../interfaces/empleado'
#Component({
selector: 'app-empleados',
templateUrl: './empleados.component.html',
styleUrls: ['./empleados.component.css']
})
export class EmpleadosComponent implements OnInit {
nuevoEmpleado = new FormGroup({
nombre: new FormControl(''),
apellido: new FormControl(''),
cargo: new FormControl('')
});
listaEmpleados: empleado[];
constructor(private empleadosService: EmpleadosService) {}
getListaEmpleados():void{
this.empleadosService.getlistaEmpleados().subscribe(empleados => this.listaEmpleados = empleados);
};
addEmpleado(){
//this.empleadosService.addEmpleado(this.nuevoEmpleado.value).subscribe(res => console.log(res));
if(!this.nuevoEmpleado){
return;
}
this.empleadosService.addEmpleado(this.nuevoEmpleado.value).subscribe(res => console.log(res));
}
ngOnInit(): void {
this.getListaEmpleados();
this.addEmpleado();
}
}
empleados.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { empleado } from '../interfaces/empleado';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class EmpleadosService {
url = 'http://localhost:3000';
constructor(private http: HttpClient) {}
getlistaEmpleados():Observable<empleado[]>{
return this.http.get<empleado[]>(this.url);
}
addEmpleado(nuevoEmpleado):Observable<Object>{
return this.http.post<empleado>(this.url , nuevoEmpleado);
}
}

Map array dont show in table

I need map a array inside my page, and show the result in a table, but the content don't show up when I compiled the page.
Can anyone help me?
When I print in console the content of a var, this is here. But the info don't show up in the page
import Layout, { siteTitle } from '../components/layout'
const fetch = require('node-fetch');
export default function Home({ devices }) {
return (
<Layout >
{devices.map((device) => (
<table>
<thead>
<th>
{device.localname} / {device.localIP}
</th>
</thead>
{console.log('1')}
<tbody>
<tr>
<td>
{device.IPaddress[0][3].value} // I put this to test, and this works fine
</td>
</tr>
{device.IPaddress.map((port) =>{
<tr>
<td>
{console.log(port[3].value), port[3].value} // here I need to work, I want to put all results of port in a TD tag, the console.log shows up the info, but the page not.
</td>
</tr>
})}
</tbody>
</table>
))}
</Layout >
)
}
export async function getStaticProps() {
const res = await fetch('http://localhost:3000')
const devices = await res.json()
return {
props: {
devices
}
}
}
As commented by #evgenifotia, change the ( for { inside the second array map works fine.
here the final function:
export default function Home({ devices }) {
return (
<Layout >
{devices.map((device) => (
<table>
{console.log('1')}
<tbody>
<tr>
<th>
{device.localname} / {device.localIP}
</th>
</tr>
{device.IPaddress.map(port =>(
<tr>
<td>
{console.log(port[3].value), port[3].value}
</td>
</tr>
))}
</tbody>
</table>
))}
</Layout >
)
}

How can i render data on change?

I'm trying to build a project in nodejs as server and firebase as my realtime db and having some problems with forwarding the data to my html.
I getting the error:
Cannot set headers after they are sent to the client
on change
I'm trying to pass the updated arr to html but can't find a way to do that.
server.js:
const locksRef = await firebase.firebase.database().ref('locks')
let arr = []
//get list of locks
const t = locksRef.on('value', (data) => {
tempResult3 = data.val()
result3 = []
const numOfKeys = Object.keys(tempResult3)
numOfKeys.forEach((x) => {
result3.push(tempResult3[x])
})
result3.forEach((k) => {
myLocks.forEach((my) => {
if (k.id == my) {
arr.push(k)
}
})
})
res.render('ListOfLocks', { arr })
})
html
<body>
<h1>ListOfHouses</h1>
<table border="1px solid black">
<thead>
<th>Name And Address</th>
</thead>
<tbody>
{{#each arr}}
<tr>
<td id="data"> {{name}} - {{address}}</td>
<td>
<form action="/seekKeys" method="post"><button name="{{locks}}" type="submit">LookForKey</button>
</form>
</td>
</tr>
{{/each}}
</tbody>
</table>
</body>

fetch api css loader

I'm using fetch API to access a REST API I developed and hosted online. But when retrieving data from the database (>60 rows) to be displayed in a section of the page, it takes about 3-5 seconds to display the data which I styled with HTML and CSS.
My question is how can i implement a css preloader to load before the actual data is displayed. And how do i know that the data has been displayed.
Below is a part of my code.
// Front end
frontend.html
<table>
<caption>User requests</caption>
<thead class="table-head">
<tr>
<th scope="col">Request Id</th>
<th scope="col">User ID</th>
<th scope="col">Brand</th>
<th scope="col">Type</th>
</tr>
</thead>
<tbody id="tablebody">
<div class="loader" id="loader"></div>
</tbody>
</table>
// file.js
fetch(url, {
method: 'GET',
headers: {'Authorization': 'Bearer ' +token}
}).then(response =>{
// Redirect the user to the login page
// If the user is not an admin
if(response.status === 401) {
window.location.replace('./Index.html');
}
return response.json()
})
.then((data) => {
let completedata = data.allRequests;
if(completedata) {
completedata.forEach((item) => {
timeStamp = new Date(item.createdon);
dateTime = timeStamp.toDateString();
theOutput +=`<tr id="listofrequests"><td data-
label="Request Id">${item.id}</td> </a>
<td data-label="Brand">${item.userid}</td>
<td data-label="Brand">${item.brand}</td>
<td data-label="Type">${item.other}</td>
<td data-label="Status">${item.name}</td>
<td data-label="Status"><a href="./Request-status.html" class="btn
view-detail" id="${item.id}" onClick="adminviewonerequest(this.id)">view</a>
</td>
<td data-label="Cancel"><button class="danger" id="${item.id}"
name="${item.name}" onClick="return cancelrequest(this.id, this.name)"><i
class="fa fa-trash"> Cancel Request</i></button></td>
</tr>`;
});
}
else {
toastr.warning(data.message);
}
document.getElementById('tablebody').innerHTML = theOutput;
})
.catch(err => console.log(err));
Use on of those already implemented load spinners How to make a loading spinner in html
Then , In your html code add <div id="loading" class="loader"></div> , Which make the loader displayed by default
and Using fetch :
fetch(YouUrl)
.then(res => {
if(res == 404){
// To hide the loader when the error is happen , There is no need to use loader
// Show some toaster notification for the user or sweet alert
document.getElementById("loading").style.display = 'none';
}
})
.then(json => {
// Here is your data so you need to hide the loader
document.getElementById("loading").style.display = 'none';
});

Resources