Skip to content

Commit

Permalink
Implement local report endpoint (#22)
Browse files Browse the repository at this point in the history
* Implement report endpoint

* Add script tags
  • Loading branch information
MrLuit authored Oct 25, 2018
1 parent ddaf2b0 commit e30b452
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export const serve = async (electronApp?: any): Promise<void> => {
app.set('views', path.join(__dirname, 'views/pages'));
app.locals.environment = process.env.NODE_ENV;
app.locals.announcement = config.announcement;
app.locals.hasSlackWebhook = typeof config.apiKeys.Slack_Webhook === 'string';

/* Compress pages */
app.use(require('compression')());
Expand Down
12 changes: 11 additions & 1 deletion src/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export interface Config {
Google_SafeBrowsing: string;
Github_WebHook: string;
VirusTotal: string;
Google_Captcha: string;
Slack_Webhook: string;
};
autoPull: {
enabled: boolean;
Expand Down Expand Up @@ -56,7 +58,9 @@ if (!fs.existsSync('./config.json')) {
apiKeys: {
Google_SafeBrowsing: undefined,
Github_WebHook: undefined,
VirusTotal: undefined
VirusTotal: undefined,
Google_Captcha: undefined,
Slack_Webhook: undefined
},
autoPull: { enabled: false },
lookups: {
Expand All @@ -77,6 +81,12 @@ if (!fs.existsSync('./config.json')) {
if (!config.apiKeys.VirusTotal) {
debug('Warning: No VirusTotal API key found');
}
if (!config.apiKeys.Google_Captcha) {
debug('Warning: No Google Captcha secret found');
}
if (!config.apiKeys.Slack_Webhook) {
debug('Warning: No Slack Webhook found');
}
if (config.lookups.DNS.servers.length > 0) {
dns.setServers(config.lookups.DNS.servers);
}
Expand Down
32 changes: 32 additions & 0 deletions src/utils/gcaptcha.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as request from 'request';
import config from './config';
import * as Debug from 'debug';

const debug = Debug('gcaptcha');

/**
* Verify a Google Captcha response
*/
export const verifyResponse = (response: string): Promise<any> => {
return new Promise((resolve, reject) => {
if (config.apiKeys.Google_Captcha) {
request.post(
'https://www.google.com/recaptcha/api/siteverify?secret=' +
encodeURIComponent(config.apiKeys.Google_Captcha) +
'&response=' +
encodeURIComponent(response),
{ json: true },
(err, response, body) => {
if (err) {
reject(err);
} else {
debug(body);
resolve(body.success);
}
}
);
} else {
reject('No Google Captcha secret found!');
}
});
};
44 changes: 40 additions & 4 deletions src/utils/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import * as url from 'url';
import config from './config';
import * as github from './github';
import * as isIpPrivate from 'private-ip';
import * as captcha from './gcaptcha';
import * as slack from './slack';
import { getGoogleSafeBrowsing, getURLScan, getVirusTotal } from './lookup';

const router = express.Router();
Expand All @@ -30,15 +32,15 @@ router.get('/api/', (req, res) => res.render('api'));
/* Report pages */
router.get('/report/', (req, res) => res.render('report'));

router.get('/report/domain/:domain', (req, res) =>
router.get('/report/domain/:domain?', (req, res) =>
res.render('report', {
domain: req.params.domain
domain: req.params.domain || true
})
);

router.get('/report/address/:address', (req, res) =>
router.get('/report/address/:address?', (req, res) =>
res.render('report', {
address: req.params.address
address: req.params.address || true
})
);

Expand Down Expand Up @@ -447,6 +449,40 @@ router.get('/api/v1/check/:search', (req, res) => {
}
});

/* Incoming user reports */
router.post('/api/v1/report/', async (req, res) => {
if (
config.apiKeys.Google_Captcha &&
config.apiKeys.Slack_Webhook &&
req.body &&
req.body.args &&
req.body.args.captcha
) {
const isValidCaptcha = await captcha.verifyResponse(req.body.args.captcha);
if (isValidCaptcha) {
slack.sendReport(req.body);
res.json({
success: true
});
} else {
res.json({
success: false,
message: 'Invalid captcha response provided'
});
}
} else if (config.apiKeys.Slack_Webhook && req.body && req.body.args && req.body.args.captcha) {
slack.sendReport(req.body);
res.json({
success: true
});
} else {
res.json({
success: false,
message: 'No captcha response provided'
});
}
});

/* Redirect old API requests */
router.get('/api/:all*?', (req, res) => res.redirect('/api/v1/' + req.params.all));

Expand Down
135 changes: 135 additions & 0 deletions src/utils/slack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import * as request from 'request';
import config from './config';
import * as Debug from 'debug';

const debug = Debug('slack');

/**
* Send report through Slack
*/
export const sendReport = (report: any): Promise<any> => {
return new Promise((resolve, reject) => {
if (config.apiKeys.Slack_Webhook) {
let message = '';
if (report.reportType == 'generalDomainReport') {
message += '*Domain*: ';
message += report.args.domain || '(none)';
message += '\n';
message += '*Reason*: ';
message += report.args.reason || '(none)';
} else if (report.reportType == 'generalAddressReport') {
message += '*Address*: ';
if (report.args.address) {
message += '<https://etherscan.io/address/' + report.args.address + '|';
}
message += report.args.address || '(none)';
if (report.args.address) {
message += '>';
}
message += '\n';
message += '*Reason*: ';
message += report.args.reason || '(none)';
} else if (report.reportType == 'uniqueReport') {
message += '*Report*: ';
message += report.args.unique || '(none)';
} else if (report.reportType == 'urgentDomainReport') {
message += '*Domain*: ';
message += report.args.domain || '(none)';
message += '\n';
message += '*Victim address*: ';
if (report.args.from) {
message += '<https://etherscan.io/address/' + report.args.from + '|';
}
message += report.args.from || '(none)';
if (report.args.from) {
message += '>';
}
message += '\n';
message += '*Attacker addresses*: ';
if (report.args.to) {
message += report.args.to
.split('\n')
.map(
address =>
'<https://etherscan.io/address/' + address + '|' + address + '>'
)
.join(', ');
} else {
message += '(none)';
}
} else if (report.reportType == 'urgentMessageAddressReport') {
message += '*Reason*: ';
message += report.args.message || '(none)';
message += '\n';
message += '*Victim address*: ';
if (report.args.from) {
message += '<https://etherscan.io/address/' + report.args.from + '|';
}
message += report.args.from || '(none)';
if (report.args.from) {
message += '>';
}
message += '\n';
message += '*Attacker addresses*: ';
if (report.args.to) {
message += report.args.to
.split('\n')
.map(
address =>
'<https://etherscan.io/address/' + address + '|' + address + '>'
)
.join(', ');
} else {
message += '(none)';
}
} else if (report.reportType == 'urgentDomainAddressReport') {
message += '*Reason*: ';
message += report.args.message || '(none)';
message += '\n';
message += '*Victim address*: ';
if (report.args.from) {
message += '<https://etherscan.io/address/' + report.args.from + '|';
}
message += report.args.from || '(none)';
if (report.args.from) {
message += '>';
}
message += '\n';
message += '*Attacker addresses*: ';
if (report.args.to) {
message += report.args.to
.split('\n')
.map(
address =>
'<https://etherscan.io/address/' + address + '|' + address + '>'
)
.join(', ');
} else {
message += '(none)';
}
} else {
message += '*Unknown reportType*: `' + report.reportType + '`\n\n';
report.args.captcha = null;
message += '```' + JSON.stringify(report.args, null, 4) + '```';
}
request.post(
config.apiKeys.Slack_Webhook,
{
json: true,
body: {
text: message
}
},
(err, response, body) => {
if (err) {
reject(err);
} else {
resolve(body);
}
}
);
} else {
reject('No Slack webhook found!');
}
});
};
21 changes: 17 additions & 4 deletions src/views/pages/report.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@
<div class="ui black label">
Domain:
</div>
<% if(typeof domain !== "undefined") { %>
<% if(typeof domain === "string") { %>
<input type="text" id="gendomain" value="<%= domain %>">
<% } else { %>
<input type="text" id="gendomain" placeholder="fake-mycrypto.com">
Expand All @@ -290,7 +290,7 @@
<div class="ui black label">
Address:
</div>
<% if(typeof address !== "undefined") { %>
<% if(typeof address === "string") { %>
<input type="text" id="address" value="<%= address %>" maxlength="42">
<% } else { %>
<input type="text" id="address" placeholder="0x0000000000000000000000000000000000000000" maxlength="42">
Expand Down Expand Up @@ -391,10 +391,23 @@
</div>
</div>
</div>
</div>
<div class="footer-container">
<% include ../partials/footer %>
<% include ../partials/footer %>
</div>

<script>
<%
if(hasSlackWebhook) {
%>
const reportEndpoint = "/api/v1/report/";
<%
} else {
%>
const reportEndpoint = "https://cryptoscamdb.org/api/v1/report/";
<%
}
%>
</script>
<% if(typeof domain !== "undefined") { %>
<script src="/js/reportdomain.js"></script>
<% } else if(typeof address !== "undefined") { %>
Expand Down
2 changes: 1 addition & 1 deletion src/views/static/js/report.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ var args = {};
function finish() {
$(".captcha").fadeOut('', function() {
$(".loading").fadeIn('', function() {
$.post("https://lu1t.nl/report.php", {
$.post(reportEndpoint, {
reportType: reportType,
args: args
}).done(function(data) {
Expand Down
2 changes: 1 addition & 1 deletion src/views/static/js/reportaddress.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var args = {};
function finish() {
$(".captcha").fadeOut('', function() {
$(".loading").fadeIn('', function() {
$.post("https://lu1t.nl/report.php", {
$.post(reportEndpoint, {
reportType: 'generalAddressReport',
args: args
}).done(function(data) {
Expand Down
2 changes: 1 addition & 1 deletion src/views/static/js/reportdomain.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ var args = {};
function finish() {
$(".captcha").fadeOut('', function() {
$(".loading").fadeIn('', function() {
$.post("https://lu1t.nl/report.php", {
$.post(reportEndpoint, {
reportType: 'generalDomainReport',
args: args
}).done(function(data) {
Expand Down

0 comments on commit e30b452

Please sign in to comment.