which-bot
Version:
detect which bot is from user-agent and is trustable
78 lines (62 loc) • 1.91 kB
text/typescript
import { RuleItem } from './rules';
const mergeRegexp = (rules: RegExp[]): RegExp => {
const sources = rules.map(item => item.source);
const flags = Array.from(new Set(Array.prototype.concat(
[],
...rules.map(item => item.flags ? item.flags.split('') : []),
)));
return new RegExp(sources.join('|'), flags.join('') || 'i');
};
export const serializeRules = (rules: RuleItem[]): Array<RuleItem & { pattern: RegExp }> => {
return rules.map((item) => {
const bots = item.bots.map(item => {
return {
...item,
pattern: new RegExp(item.pattern, item.pattern instanceof RegExp && item.pattern.flags || 'i'),
};
});
return {
...item,
bots,
pattern: mergeRegexp(bots.map((item) => item.pattern)),
};
});
};
export const match = (ua: string, rules: Array<RuleItem & { pattern: RegExp }>) => {
for (const group of rules) {
if (!ua.match(group.pattern)) {
continue;
}
for (const bot of group.bots) {
if (!ua.match(bot.pattern)) {
continue;
}
return {
company: group.company,
name: bot.name,
hosts: group.hosts,
};
}
return false;
}
return false;
};
export const isValidIp = async (hosts: string[], ip: string) => {
const { reverse } = require('dns').promises;
if (typeof reverse !== 'function') {
return false;
}
try {
const resolved: string[] = await reverse(ip);
for (const item of resolved) {
for (const host of hosts) {
if (item.endsWith(host)) {
return true;
}
}
}
return false;
} catch (e) {
return false;
}
};