← back to Rentv 2026
chore: harden sublease (listing_url XSS guard, DELETE id validation), refactor, v0.5.0 (session close)
6e2fe1310d32dbbd8d19cfd16a17ecad2f016edf · 2026-07-22 20:24:42 -0700 · Steve
Files touched
M package-lock.jsonM package.jsonM public/desk.htmlM server.js
Diff
commit 6e2fe1310d32dbbd8d19cfd16a17ecad2f016edf
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Jul 22 20:24:42 2026 -0700
chore: harden sublease (listing_url XSS guard, DELETE id validation), refactor, v0.5.0 (session close)
---
package-lock.json | 4 ++--
package.json | 2 +-
public/desk.html | 3 +--
server.js | 6 +++++-
4 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 738bb014..7cb8addd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "rentv-v1",
- "version": "0.4.0",
+ "version": "0.5.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "rentv-v1",
- "version": "0.4.0",
+ "version": "0.5.0",
"dependencies": {
"express": "^4.21.2"
}
diff --git a/package.json b/package.json
index 49c9fe27..d6d27833 100644
--- a/package.json
+++ b/package.json
@@ -1 +1 @@
-{"name":"rentv-v1","version":"0.4.0","private":true,"main":"server.js","scripts":{"start":"node server.js","pull":"node scripts/pull-news.mjs"},"dependencies":{"express":"^4.21.2"}}
\ No newline at end of file
+{"name":"rentv-v1","version":"0.5.0","private":true,"main":"server.js","scripts":{"start":"node server.js","pull":"node scripts/pull-news.mjs"},"dependencies":{"express":"^4.21.2"}}
\ No newline at end of file
diff --git a/public/desk.html b/public/desk.html
index 1703f7a9..5a969d03 100644
--- a/public/desk.html
+++ b/public/desk.html
@@ -99,7 +99,7 @@ function actions(k,x){
if(k==='firms')return [A(LI_C(x.name),'🏢','LinkedIn'),A(WEB(x.name),'🌐','Website'),A(MAPS(x.name+' '+loc(x)),'📍','HQ / Map'),x.license_no?A(DRE(x.license_no),'🪪','DRE'):'',A(GOOG(x.name+' brokers '+loc(x)),'🔎','Google')].filter(Boolean).join('');
if(k==='owners'){const ad=[x.address,x.city].filter(Boolean).join(', ');return [A(MAPS(ad),'📍','Map'),A(GOOG(ad+' '+(x.use_desc||'')+' owner'),'🔎','Owner / deal'),A('https://www.google.com/maps/@?api=1&map_action=pano&viewpoint='+enc(ad),'📸','Street View'),A(ASSR(x.ain),'🏛️','Assessor')].join('');}
if(k==='sublease'){const ad=[x.address,x.city].filter(Boolean).join(', ');return [
- x.listing_url?A(x.listing_url,'🔗','Listing'):'',
+ (x.listing_url&&/^https?:\/\//i.test(x.listing_url))?A(x.listing_url,'🔗','Listing'):'',
A(MAPS(ad),'📍','Map'),
A('https://www.google.com/maps/@?api=1&map_action=pano&viewpoint='+enc(ad),'📸','Street View'),
x.broker_name?A(LI_P(x.broker_name,x.firm_name),'👤','Broker'):'',
@@ -164,7 +164,6 @@ function renderAll(){directory();analytics();applyScopeViews();}
function directory(){
const rows=scopeData();
$('v-directory').innerHTML=`<div class="md"><div class="list"><div class="search"><input id="dq" placeholder="Search ${D.scope}…"><div class="fresh" id="dcount" style="padding:7px 2px 0"></div></div><div class="rows" id="drows"></div></div><div class="detail" id="ddetail"></div></div>`;
- const q='';
function list(){let r=rows.slice();const v=($('dq').value||'').toLowerCase();if(v)r=r.filter(x=>JSON.stringify(x).toLowerCase().includes(v));return r;}
function detail(x){if(!x){$('ddetail').innerHTML='';return;}
const grid=D.scope==='sublease'?[['SqFt',x.sqft?Number(x.sqft).toLocaleString():'—'],['Asking',subRate(x)],['Term',x.term_months?x.term_months+' mo':'—'],['Available',x.available_date?dstr(x.available_date):'Now'],['Sublandlord',x.sublandlord||'—'],['Listing broker',x.firm_name||'—']]:D.scope==='owners'?[['Assessed',shortUsd(x.assessed_total)],['SqFt',(x.sqft||0).toLocaleString()],['Built',x.year_built||'—'],['AIN',x.ain]]:D.scope==='firms'?[['Agents',(x.agent_count||0).toLocaleString()],['HQ',loc(x)||'—'],['License',x.license_no||'—'],['Source',x.source||'—']]:[['License',x.license_no||'—'],['Type',x.license_type||'—'],['Firm',x.firm_name||'—'],['City',x.city||'—']];
diff --git a/server.js b/server.js
index 083f8b48..1507d81f 100644
--- a/server.js
+++ b/server.js
@@ -266,7 +266,11 @@ function adminGate(req, res, next) {
}
app.get('/desk-admin', adminGate, (_req, res) => res.sendFile(path.join(__dirname, 'admin', 'desk-admin.html')));
app.post('/api/admin/sublease', adminGate, (req, res) => usreWrite('POST', '/api/admin/sublease', req, res));
-app.delete('/api/admin/sublease/:id', adminGate, (req, res) => usreWrite('DELETE', '/api/admin/sublease/' + encodeURIComponent(req.params.id), req, res));
+app.delete('/api/admin/sublease/:id', adminGate, (req, res) => {
+ const id = String(req.params.id).replace(/[^\d]/g, '');
+ if (!id) return res.status(400).json({ ok: false, error: 'bad id' });
+ return usreWrite('DELETE', '/api/admin/sublease/' + id, req, res);
+});
app.use(express.static(PUB, { extensions: ['html'] }));
app.listen(PORT, () => console.log('rentv-v1 (full site, gated, live data) on ' + PORT));
← 85dbfc62 auto-save: 2026-07-22T20:16:30 (3 files) — data/markets.json
·
back to Rentv 2026
·
auto-save: 2026-07-22T20:46:37 (3 files) — data/markets.json 4a206b7a →