secure user input

This commit is contained in:
j.mei7
2022-04-03 17:42:22 +02:00
parent eddfa544a4
commit 12dd3f9e53
5 changed files with 144 additions and 40 deletions

Binary file not shown.

View File

@@ -0,0 +1,13 @@
function secure(text){
text = text.replace(/'/g, "\\u0027");
return text;
}
function decode(text){
text = text.replace(/\\u0027/g, "'");
return text;
}
module.exports = {
secure, decode
}

View File

@@ -4,7 +4,7 @@ const app = express();
const sqlite3 = require('sqlite3'); const sqlite3 = require('sqlite3');
const db = new sqlite3.Database("database.db") const db = new sqlite3.Database("database.db")
const port = process.env.PORT || 5000; const port = process.env.PORT || 5000;
const securePostData = require('./securePostData');
// body parser // body parser
const bodyParser = require('body-parser'); const bodyParser = require('body-parser');
app.use(bodyParser.json()); app.use(bodyParser.json());
@@ -29,7 +29,11 @@ app.get('/idea/:id', (req, res) => {
res.send({title: "Error", content: "Error fetching idea"}); res.send({title: "Error", content: "Error fetching idea"});
}else{ }else{
if(rows.length > 0){ if(rows.length > 0){
res.json(rows[0]); // De-Formatting
rows[0].title = securePostData.decode(rows[0].title);
rows[0].content = securePostData.decode(rows[0].content);
res.json(rows[0]);
}else{ }else{
res.send({title: "Error", content: "Idea not found"}); res.send({title: "Error", content: "Idea not found"});
} }
@@ -42,6 +46,11 @@ app.get('/ideas', (req, res) => {
if (err) { if (err) {
res.send({title: "Error", content: "Error fetching ideas"}); res.send({title: "Error", content: "Error fetching ideas"});
}else{ }else{
for (let i = 0; i < rows.length; i++) {
// De-Formatting
rows[i].title = securePostData.decode(rows[i].title);
rows[i].content = securePostData.decode(rows[i].content);
}
res.json(rows); res.json(rows);
} }
}); });
@@ -49,11 +58,40 @@ app.get('/ideas', (req, res) => {
app.post('/idea/update/:id', (req, res) => { app.post('/idea/update/:id', (req, res) => {
db.run(`UPDATE ideas SET title = '${req.body.title}', content = '${req.body.content}' WHERE id = ${req.params.id}`, (err) => {
// Validate POST
if(!req.body.title || req.body.title.replace(/\s/g, '').length === 0){
res.send({title: "Error", type:"title", message: "Title is required"});
return;
}else if(!req.body.content || req.body.content.replace(/\s/g, '').length === 0){
res.send({title: "Error", type:"content", message: "Content is required"});
return;
}
let regexPattern = /^[a-zA-ZÀ-úÀ-ÿÀ-ÿÀ-ÖØ-öø-ÿ0-9ßäöüÄÖÜ!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?`´\s]*$/;
if(!regexPattern.test(req.body.title)){
res.send({title: "Error", type:"title", message: "Title contains invalid characters"});
return;
}else if(!regexPattern.test(req.body.content)){
res.send({title: "Error", type:"content", message: "Content contains invalid characters"});
return;
}
// replace ' with \u0027
let title = securePostData.secure(req.body.title);
let content = securePostData.secure(req.body.content);
db.run(`UPDATE ideas SET title = '${title}', content = '${content}' WHERE id = ${req.params.id}`, (err) => {
if (err) { if (err) {
res.send({title: "Error", content: "Error updating idea"}); res.send({title: "Error", type:"saving", message: "Error updating idea"});
}else{ }else{
res.send({title: "Success", content: "Idea updated"}); res.send({title: "Success", type:"saving", message: "Idea updated"});
} }
}); });
}); });

View File

@@ -7,25 +7,28 @@ function IdeaContent(){
let [title, setTitle] = useState(""); let [title, setTitle] = useState("");
let [content, setContent] = useState("") let [content, setContent] = useState("")
let [saved , setSaved] = useState(false); let [saved , setSaved] = useState(false);
let [seconds, setSeconds] = useState(0); let [intervalTime, setintervalTime] = useState(0);
let [contentError, setContentError] = useState("");
let [titleError, setTitleError] = useState("");
let secondsSaveInterval = 3;
//let secondsSaveInterval = 0;
// TIMER // TIMER
useEffect(() => { useEffect(() => {
const interval = setInterval(() => { const interval = setInterval(() => {
setSeconds(seconds => seconds + 1); setintervalTime(intervalTime => intervalTime + 1);
if(seconds > secondsSaveInterval){ // save every > secondsSaveInterval seconds if(intervalTime > 0){
saveData(); saveData();
setSeconds(0); setintervalTime(0);
} }
}, 1000); }, 500);
return () => clearInterval(interval); return () => clearInterval(interval);
}); });
const saveData = async () => { const saveData = async () => {
let ideaData = { let ideaData = {
title: title, title: title,
@@ -44,7 +47,18 @@ function IdeaContent(){
if(res.title === "Success"){ if(res.title === "Success"){
setSaved(true); setSaved(true);
} else { setContentError("");
setTitleError("");
} else if(res.title === "Error"){
if(res.type === "content"){
setContentError(res.message);
setTitleError("");
} else if(res.type === "title"){
setTitleError(res.message);
setContentError("");
}
setSaved(false);
}else{
setSaved(false); setSaved(false);
} }
} }
@@ -69,14 +83,20 @@ function IdeaContent(){
return( return(
<div className="ideaContent"> <div className="ideaContent">
<div className="head"> <div className="head">
<input type="text" name="title" <label htmlFor="title">
value={title} <input type="text" name="title"
onChange={(e) => { setTitle(e.target.value); setSaved(false) }} className={titleError ? "input-error" : ""}
placeholder="Insert a title"/> value={title}
onChange={(e) => { setTitle(e.target.value); setSaved(false) }}
placeholder="Insert a title"/>
<small className="error-text">{titleError}</small>
</label>
<small>{saved ? "Saved!": "Saving..."}</small> <small>{saved ? "Saved!": "Saving..."}</small>
</div> </div>
<div className="textAreaContainer"> <div className="textAreaContainer">
<textarea value={content} onChange={(e) => { setContent(e.target.value); setSaved(false)}}></textarea> <small className="error-text">{contentError}</small>
<textarea className={contentError ? "input-error" : ""} value={content} onChange={(e) => { setContent(e.target.value); setSaved(false)}}></textarea>
</div> </div>
</div> </div>
) )

View File

@@ -6,38 +6,46 @@
.head{ .head{
padding-top: 20px; padding-top: 20px;
padding-bottom: 20px; padding-bottom: 50px;
margin-bottom: 20px; margin-bottom: 20px;
border-bottom: 2px solid rgba(87, 87, 87, 0.3); border-bottom: 2px solid rgba(87, 87, 87, 0.3);
width: 100%; width: 100%;
display: block; display: block;
input{ label{
background-color: transparent;
border: 0px;
border-bottom: 2px solid rgba(87, 87, 87, 0.5);
font-size: 24pt;
color: white;
outline:none;
margin-left: 50px; margin-left: 50px;
font-weight: bold; margin-bottom: 20px;
width: 60%; width: 60%;
transition: 100ms; display: block;
transition-timing-function: linear; float: left;
&::placeholder{ input{
color: rgba(255, 255, 255, 0.44); background-color: transparent;
border: 0px;
border-bottom: 2px solid rgba(87, 87, 87, 0.5);
font-size: 24pt;
color: white;
outline:none;
font-weight: bold; font-weight: bold;
} width: 100%;
transition: 100ms;
&:hover{ transition-timing-function: linear;
border-color: rgb(80, 209, 160);
} &::placeholder{
color: rgba(255, 255, 255, 0.44);
&:focus{ font-weight: bold;
border-color: rgb(80, 209, 160); }
&:hover{
border-color: rgb(80, 209, 160);
}
&:focus{
border-color: rgb(80, 209, 160);
}
} }
} }
} }
.textAreaContainer{ .textAreaContainer{
@@ -48,7 +56,7 @@
textarea{ textarea{
outline: 0; outline: 0;
display: block; display: block;
width: calc(100% - 40px); width: calc(100% - 43px);
height: 100%; height: 100%;
background-color: rgba(71, 71, 71, 0.171); background-color: rgba(71, 71, 71, 0.171);
border: 0px solid transparent; border: 0px solid transparent;
@@ -60,6 +68,31 @@
padding-top: 10px; padding-top: 10px;
padding-bottom: 10px; padding-bottom: 10px;
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
border-left: 3px solid transparent;
transition: 100ms;
transition-timing-function: linear;
&:hover{
border-color: rgb(80, 209, 160);
}
&:focus{
border-color: rgb(80, 209, 160);
}
}
.error-text{
padding-left: 23px;
} }
} }
.input-error{
border-color: rgb(255, 45, 45) !important;
}
.error-text{
color:rgb(255, 45, 45);
font-weight: bold;
cursor: text;
}
} }