Implement attachment downloading
parent
006e180553
commit
b8634a9269
|
@ -431,7 +431,7 @@ class Syncer
|
||||||
{
|
{
|
||||||
byid[a.contentId||''] = a;
|
byid[a.contentId||''] = a;
|
||||||
}
|
}
|
||||||
msg.html = msg.html.replace(/(<img[^<>]*src=["']?)cid:([^'"\s]{1,256})/g, (m, m1, m2) =>
|
msg.html = (msg.html||'').replace(/(<img[^<>]*src=["']?)cid:([^'"\s]{1,256})/g, (m, m1, m2) =>
|
||||||
{
|
{
|
||||||
if (!byid[m2])
|
if (!byid[m2])
|
||||||
{
|
{
|
||||||
|
@ -618,12 +618,12 @@ class Syncer
|
||||||
body_html: obj.html,
|
body_html: obj.html,
|
||||||
body_html_text: obj.html.replace(/<style[^>]*>.*<\/style\s*>|<\/?[^>]*>/g, ''),
|
body_html_text: obj.html.replace(/<style[^>]*>.*<\/style\s*>|<\/?[^>]*>/g, ''),
|
||||||
};
|
};
|
||||||
/*await SQL.update(
|
await SQL.update(
|
||||||
this.pg, 'messages m', {
|
this.pg, 'messages m', {
|
||||||
...upd,
|
...upd,
|
||||||
'props = props || ?': [ { attachments: obj.attachments } ]
|
'props = props || ?': [ { attachments: obj.attachments } ]
|
||||||
}, { folder_id: boxId, uid: msg[0].uid }
|
}, { folder_id: boxId, uid: msg[0].uid }
|
||||||
);*/
|
);
|
||||||
if (messages.length == 1)
|
if (messages.length == 1)
|
||||||
{
|
{
|
||||||
upd.props = { attachments: obj.attachments };
|
upd.props = { attachments: obj.attachments };
|
||||||
|
|
41
SyncerWeb.js
41
SyncerWeb.js
|
@ -6,6 +6,7 @@ const express_session = require('express-session');
|
||||||
const morgan = require('morgan');
|
const morgan = require('morgan');
|
||||||
const bodyparser = require('body-parser');
|
const bodyparser = require('body-parser');
|
||||||
const multer = require('multer');
|
const multer = require('multer');
|
||||||
|
const rawurlencode = require('rawurlencode');
|
||||||
|
|
||||||
const SQL = require('./select-builder-pgsql.js');
|
const SQL = require('./select-builder-pgsql.js');
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ class SyncerWeb
|
||||||
this.app.get('/groups', wrapAsync(this, 'get_groups'));
|
this.app.get('/groups', wrapAsync(this, 'get_groups'));
|
||||||
this.app.get('/messages', wrapAsync(this, 'get_messages'));
|
this.app.get('/messages', wrapAsync(this, 'get_messages'));
|
||||||
this.app.get('/message', wrapAsync(this, 'get_message'));
|
this.app.get('/message', wrapAsync(this, 'get_message'));
|
||||||
|
this.app.get('/attachment', wrapAsync(this, 'get_attachment'));
|
||||||
this.app.post('/sync', wrapAsync(this, 'post_sync'));
|
this.app.post('/sync', wrapAsync(this, 'post_sync'));
|
||||||
this.syncer.events.on('sync', (params) => this.syncer_sync(params));
|
this.syncer.events.on('sync', (params) => this.syncer_sync(params));
|
||||||
}
|
}
|
||||||
|
@ -256,6 +258,45 @@ class SyncerWeb
|
||||||
return res.send({ msg: msg });
|
return res.send({ msg: msg });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async get_attachment(req, res)
|
||||||
|
{
|
||||||
|
if (this.cfg.login && (!req.session || !req.session.auth))
|
||||||
|
{
|
||||||
|
return res.sendStatus(401);
|
||||||
|
}
|
||||||
|
let msgId = req.query.msgId;
|
||||||
|
let sha1 = (req.query.sha1||'').replace(/[^0-9a-fA-F]+/g, '').toLowerCase();
|
||||||
|
if (!msgId || !sha1)
|
||||||
|
{
|
||||||
|
return res.sendStatus(404);
|
||||||
|
}
|
||||||
|
let msg = await SQL.select(
|
||||||
|
this.pg, 'messages', '*', { id: msgId }, null, SQL.MS_ROW
|
||||||
|
);
|
||||||
|
let a = ((msg.props||{}).attachments||[]).filter(a => a.sha1 == sha1)[0];
|
||||||
|
if (!a)
|
||||||
|
{
|
||||||
|
return res.sendStatus(404);
|
||||||
|
}
|
||||||
|
if (new RegExp(
|
||||||
|
// HTML may contain cookie-stealing JavaScript and web bugs
|
||||||
|
'^text/(html|(x-)?javascript)$|^application/x-shellscript$'+
|
||||||
|
// PHP/Perl/Bash/etc scripts may execute arbitrary code on the server
|
||||||
|
'|php|perl|python|bash|x-c?sh(e|$)'+
|
||||||
|
// Client-side hazards on Internet Explorer
|
||||||
|
'|^text/scriptlet$|^application/x-msdownload$'+
|
||||||
|
// Windows metafile, client-side vulnerability on some systems
|
||||||
|
'|^application/x-msmetafile$', 'is'
|
||||||
|
).exec(a.mimetype))
|
||||||
|
{
|
||||||
|
a.mimetype = 'application/octet-stream';
|
||||||
|
}
|
||||||
|
res.set('Content-Type', a.mimetype);
|
||||||
|
res.set('Content-Disposition', 'attachment; filename*=UTF-8\'\''+rawurlencode(a.name));
|
||||||
|
await new Promise((r, j) => res.sendFile(this.syncer.files_path+'/'+sha1.substr(0, 2)+'/'+sha1.substr(2, 2)+'/'+sha1+'.bin', r));
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
|
||||||
syncer_sync(params)
|
syncer_sync(params)
|
||||||
{
|
{
|
||||||
this.io.emit('sync', params);
|
this.io.emit('sync', params);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* TODO:
|
* TODO:
|
||||||
|
* + скачивание вложений
|
||||||
* - пометка прочитанным, просмотренным (seen)
|
* - пометка прочитанным, просмотренным (seen)
|
||||||
* - фоновая индексация всех текстов сообщений в ящике
|
* - фоновая индексация всех текстов сообщений в ящике
|
||||||
* - скачивание вложений
|
|
||||||
* - написание сообщений
|
* - написание сообщений
|
||||||
* - ответ, пересылка
|
* - ответ, пересылка
|
||||||
* - подсказка адресов
|
* - подсказка адресов
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
"nodemailer": "latest",
|
"nodemailer": "latest",
|
||||||
"pg": "^7.10.0",
|
"pg": "^7.10.0",
|
||||||
"pg-escape": "^0.2.0",
|
"pg-escape": "^0.2.0",
|
||||||
|
"rawurlencode": "^1.0.2",
|
||||||
"socket.io": "latest"
|
"socket.io": "latest"
|
||||||
},
|
},
|
||||||
"peerDependencies": {},
|
"peerDependencies": {},
|
||||||
|
|
Loading…
Reference in New Issue