♻️ 'pogo' -> 'fastify'
parent
f26cb62acb
commit
96d442c505
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"tasks": {
|
||||
"start": "deno run --allow-read --allow-env --allow-sys=hostname --allow-net --allow-run ./main.js"
|
||||
}
|
||||
}
|
47
main.js
47
main.js
|
@ -1,8 +1,6 @@
|
|||
import * as Sentry from 'npm:@sentry/node@7.28.1';
|
||||
import pogo from 'https://deno.land/x/pogo@v0.6.0/main.ts';
|
||||
import {
|
||||
createServerHelper
|
||||
} from 'https://git.kaki87.net/KaKi87/pogo-helpers/raw/commit/a80ff83ec392106f783f531b37e0f722d65e4d11/mod.js';
|
||||
import createFastify from 'npm:fastify@4.22.2';
|
||||
import fastifyCors from 'npm:@fastify/cors@8.3.0';
|
||||
|
||||
import dns from './src/dns.js';
|
||||
import whois from './src/whois.js';
|
||||
|
@ -30,37 +28,16 @@ globalThis.addEventListener(
|
|||
}
|
||||
);
|
||||
|
||||
const
|
||||
server = pogo.server({
|
||||
port
|
||||
}),
|
||||
{
|
||||
createRoute
|
||||
} = createServerHelper(
|
||||
server,
|
||||
{
|
||||
isCors: true,
|
||||
onError
|
||||
}
|
||||
);
|
||||
const fastify = createFastify();
|
||||
|
||||
createRoute({
|
||||
method: 'GET',
|
||||
path: '/',
|
||||
handler: (
|
||||
request,
|
||||
h,
|
||||
{
|
||||
response
|
||||
}
|
||||
) => {
|
||||
response.redirect('https://git.kaki87.net/KaKi87/deno-api').permanent();
|
||||
return response;
|
||||
}
|
||||
});
|
||||
fastify.register(fastifyCors);
|
||||
fastify.setValidatorCompiler(({ schema }) => data => schema.validate(data));
|
||||
|
||||
createRoute(dns);
|
||||
createRoute(whois);
|
||||
createRoute(favicon);
|
||||
fastify.get('/', (request, reply) => reply.redirect(301, 'https://git.kaki87.net/KaKi87/deno-api'));
|
||||
|
||||
server.start();
|
||||
fastify.register(dns);
|
||||
fastify.register(whois);
|
||||
fastify.register(favicon);
|
||||
|
||||
await fastify.listen({ port });
|
||||
console.log(`Listening to localhost:${port}`);
|
229
src/dns.js
229
src/dns.js
|
@ -19,126 +19,123 @@ import exec from '../lib/exec.js';
|
|||
* @response {boolean} success Whether the request was successful.
|
||||
* @response {DnsResponseBodyData[]} data The resulting records.
|
||||
*/
|
||||
export default {
|
||||
method: 'GET',
|
||||
path: '/dns/{hostname}',
|
||||
schema: Joi.object({
|
||||
path: Joi.object({
|
||||
hostname: Joi
|
||||
.string()
|
||||
.hostname()
|
||||
.required()
|
||||
}),
|
||||
params: Joi.object({
|
||||
nameserver: Joi
|
||||
.string()
|
||||
.hostname()
|
||||
.default('8.8.8.8'),
|
||||
record: Joi
|
||||
.string()
|
||||
.valid(
|
||||
'ANY',
|
||||
'A',
|
||||
'AAAA',
|
||||
'AFSDB',
|
||||
'APL',
|
||||
'AXFR',
|
||||
'CAA',
|
||||
'CDNSKEY',
|
||||
'CDS',
|
||||
'CERT',
|
||||
'CNAME',
|
||||
'CSYNC',
|
||||
'DHCID',
|
||||
'DLV',
|
||||
'DNAME',
|
||||
'DNSKEY',
|
||||
'DS',
|
||||
'EUI48',
|
||||
'EUI64',
|
||||
'HINFO',
|
||||
'HIP',
|
||||
'HTTPS',
|
||||
'IPSECKEY',
|
||||
'IXFR',
|
||||
'KEY',
|
||||
'KX',
|
||||
'LOC',
|
||||
'MX',
|
||||
'NAPTR',
|
||||
'NS',
|
||||
'NSEC3',
|
||||
'NSEC3PARAM',
|
||||
'NSEC',
|
||||
'NXT',
|
||||
'OPENPGPKEY',
|
||||
'OPT',
|
||||
'PTR',
|
||||
'RP',
|
||||
'RRSIG',
|
||||
'SIG',
|
||||
'SMIMEA',
|
||||
'SOA',
|
||||
'SSHFP',
|
||||
'SVCB',
|
||||
'SRV',
|
||||
'TA',
|
||||
'TKEY',
|
||||
'TLSA',
|
||||
'TSIG',
|
||||
'TXT',
|
||||
'URI',
|
||||
'ZONEMD'
|
||||
)
|
||||
.default('ANY')
|
||||
})
|
||||
}),
|
||||
handler: async (
|
||||
request,
|
||||
h,
|
||||
export default async fastify => {
|
||||
fastify.get(
|
||||
'/dns/:hostname',
|
||||
{
|
||||
path: {
|
||||
schema: {
|
||||
params: Joi.object({
|
||||
hostname: Joi
|
||||
.string()
|
||||
.hostname()
|
||||
.required()
|
||||
}),
|
||||
query: Joi.object({
|
||||
nameserver: Joi
|
||||
.string()
|
||||
.hostname()
|
||||
.default('8.8.8.8'),
|
||||
record: Joi
|
||||
.string()
|
||||
.valid(
|
||||
'ANY',
|
||||
'A',
|
||||
'AAAA',
|
||||
'AFSDB',
|
||||
'APL',
|
||||
'AXFR',
|
||||
'CAA',
|
||||
'CDNSKEY',
|
||||
'CDS',
|
||||
'CERT',
|
||||
'CNAME',
|
||||
'CSYNC',
|
||||
'DHCID',
|
||||
'DLV',
|
||||
'DNAME',
|
||||
'DNSKEY',
|
||||
'DS',
|
||||
'EUI48',
|
||||
'EUI64',
|
||||
'HINFO',
|
||||
'HIP',
|
||||
'HTTPS',
|
||||
'IPSECKEY',
|
||||
'IXFR',
|
||||
'KEY',
|
||||
'KX',
|
||||
'LOC',
|
||||
'MX',
|
||||
'NAPTR',
|
||||
'NS',
|
||||
'NSEC3',
|
||||
'NSEC3PARAM',
|
||||
'NSEC',
|
||||
'NXT',
|
||||
'OPENPGPKEY',
|
||||
'OPT',
|
||||
'PTR',
|
||||
'RP',
|
||||
'RRSIG',
|
||||
'SIG',
|
||||
'SMIMEA',
|
||||
'SOA',
|
||||
'SSHFP',
|
||||
'SVCB',
|
||||
'SRV',
|
||||
'TA',
|
||||
'TKEY',
|
||||
'TLSA',
|
||||
'TSIG',
|
||||
'TXT',
|
||||
'URI',
|
||||
'ZONEMD'
|
||||
)
|
||||
.default('ANY')
|
||||
})
|
||||
}
|
||||
},
|
||||
async ({
|
||||
params: {
|
||||
hostname
|
||||
},
|
||||
params: {
|
||||
query: {
|
||||
nameserver,
|
||||
record
|
||||
},
|
||||
response
|
||||
}
|
||||
}) => {
|
||||
const {
|
||||
stdout,
|
||||
stderr
|
||||
} = await exec(
|
||||
'dig',
|
||||
`@${nameserver}`,
|
||||
hostname,
|
||||
record,
|
||||
'+noall',
|
||||
'+answer'
|
||||
);
|
||||
return {
|
||||
success: stdout && !stderr,
|
||||
data: stdout
|
||||
.split('\n')
|
||||
.filter(Boolean)
|
||||
.map(line => {
|
||||
const [
|
||||
domain,
|
||||
ttl
|
||||
,,
|
||||
type,
|
||||
...value
|
||||
] = line.split(/\s+/g);
|
||||
return {
|
||||
domain,
|
||||
ttl: parseInt(ttl),
|
||||
type,
|
||||
value: value.join(' ')
|
||||
};
|
||||
})
|
||||
};
|
||||
}
|
||||
) => {
|
||||
const {
|
||||
stdout,
|
||||
stderr
|
||||
} = await exec(
|
||||
'dig',
|
||||
`@${nameserver}`,
|
||||
hostname,
|
||||
record,
|
||||
'+noall',
|
||||
'+answer'
|
||||
);
|
||||
response.body = {
|
||||
success: stdout && !stderr,
|
||||
data: stdout
|
||||
.split('\n')
|
||||
.filter(Boolean)
|
||||
.map(line => {
|
||||
const [
|
||||
domain,
|
||||
ttl
|
||||
,,
|
||||
type,
|
||||
...value
|
||||
] = line.split(/\s+/g);
|
||||
return {
|
||||
domain,
|
||||
ttl: parseInt(ttl),
|
||||
type,
|
||||
value: value.join(' ')
|
||||
};
|
||||
})
|
||||
};
|
||||
return response;
|
||||
}
|
||||
);
|
||||
};
|
115
src/favicon.js
115
src/favicon.js
|
@ -62,71 +62,64 @@ const
|
|||
* @query {string} [provider=auto] The provider to get the favicon from.
|
||||
* @response data The resulting favicon.
|
||||
*/
|
||||
export default {
|
||||
method: 'GET',
|
||||
path: '/favicon/{hostname}',
|
||||
schema: Joi.object({
|
||||
path: Joi.object({
|
||||
hostname: Joi
|
||||
.string()
|
||||
.hostname()
|
||||
.required()
|
||||
}),
|
||||
params: Joi.object({
|
||||
provider: Joi
|
||||
.string()
|
||||
.valid(
|
||||
'auto',
|
||||
...providers
|
||||
)
|
||||
.default('auto')
|
||||
})
|
||||
}),
|
||||
handler: async (
|
||||
request,
|
||||
h,
|
||||
export default async fastify => {
|
||||
fastify.get(
|
||||
'/favicon/:hostname',
|
||||
{
|
||||
path: {
|
||||
schema: {
|
||||
params: Joi.object({
|
||||
hostname: Joi
|
||||
.string()
|
||||
.hostname()
|
||||
.required()
|
||||
}),
|
||||
query: Joi.object({
|
||||
provider: Joi
|
||||
.string()
|
||||
.valid(
|
||||
'auto',
|
||||
...providers
|
||||
)
|
||||
.default('auto')
|
||||
})
|
||||
}
|
||||
},
|
||||
async ({
|
||||
params: {
|
||||
hostname
|
||||
},
|
||||
params: {
|
||||
query: {
|
||||
provider
|
||||
},
|
||||
response
|
||||
}
|
||||
) => {
|
||||
let
|
||||
data,
|
||||
type;
|
||||
if(provider === 'auto'){
|
||||
for(const provider of providers){
|
||||
try {
|
||||
({
|
||||
data,
|
||||
type
|
||||
} = await fetchFaviconFromProvider({
|
||||
provider,
|
||||
hostname
|
||||
}));
|
||||
if(data && type)
|
||||
break;
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
}, reply) => {
|
||||
let
|
||||
data,
|
||||
type;
|
||||
if(provider === 'auto'){
|
||||
for(const provider of providers){
|
||||
try {
|
||||
({
|
||||
data,
|
||||
type
|
||||
} = await fetchFaviconFromProvider({
|
||||
provider,
|
||||
hostname
|
||||
}));
|
||||
if(data && type)
|
||||
break;
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
}
|
||||
else ({
|
||||
data,
|
||||
type
|
||||
} = await fetchFaviconFromProvider({
|
||||
provider,
|
||||
hostname
|
||||
}));
|
||||
if(data && type) reply.type(type).send(data);
|
||||
else reply.code(500);
|
||||
}
|
||||
else ({
|
||||
data,
|
||||
type
|
||||
} = await fetchFaviconFromProvider({
|
||||
provider,
|
||||
hostname
|
||||
}));
|
||||
if(data && type){
|
||||
response.body = data;
|
||||
response.type(type);
|
||||
}
|
||||
else
|
||||
response.code(500);
|
||||
return response;
|
||||
}
|
||||
);
|
||||
};
|
137
src/whois.js
137
src/whois.js
|
@ -10,85 +10,82 @@ import exec from '../lib/exec.js';
|
|||
* @response {boolean} success Whether the request was successful.
|
||||
* @response {string|object} data The resulting info.
|
||||
*/
|
||||
export default {
|
||||
method: 'GET',
|
||||
path: '/whois/{hostname}',
|
||||
schema: Joi.object({
|
||||
path: Joi.object({
|
||||
hostname: Joi
|
||||
.string()
|
||||
.hostname()
|
||||
.required()
|
||||
}),
|
||||
params: Joi.object({
|
||||
format: Joi
|
||||
.string()
|
||||
.valid(
|
||||
'text',
|
||||
'json',
|
||||
'nestedJson'
|
||||
)
|
||||
.default('json')
|
||||
})
|
||||
}),
|
||||
handler: async (
|
||||
request,
|
||||
h,
|
||||
export default async fastify => {
|
||||
fastify.get(
|
||||
'/whois/:hostname',
|
||||
{
|
||||
path: {
|
||||
schema: {
|
||||
params: Joi.object({
|
||||
hostname: Joi
|
||||
.string()
|
||||
.hostname()
|
||||
.required()
|
||||
}),
|
||||
query: Joi.object({
|
||||
format: Joi
|
||||
.string()
|
||||
.valid(
|
||||
'text',
|
||||
'json',
|
||||
'nestedJson'
|
||||
)
|
||||
.default('json')
|
||||
})
|
||||
}
|
||||
},
|
||||
async ({
|
||||
params: {
|
||||
hostname
|
||||
},
|
||||
params: {
|
||||
query: {
|
||||
format
|
||||
},
|
||||
response
|
||||
}
|
||||
) => {
|
||||
const {
|
||||
stdout,
|
||||
stderr
|
||||
} = await exec(
|
||||
'whois',
|
||||
hostname
|
||||
);
|
||||
let data;
|
||||
switch(format){
|
||||
case 'text': {
|
||||
data = stdout;
|
||||
break;
|
||||
}
|
||||
case 'json':
|
||||
case 'nestedJson': {
|
||||
data = {};
|
||||
for(const line of stdout.split('\n')){
|
||||
const [, key, value] = line.match(/^\s*([\w\s]+)[^\w]?\s+(.+)$/) || [];
|
||||
if(key && value){
|
||||
if(format === 'json'){
|
||||
if(!data[key])
|
||||
data[key] = [];
|
||||
data[key].push(value);
|
||||
}
|
||||
else if(format === 'nestedJson'){
|
||||
const keys = key.split(/\s+/g);
|
||||
let parentObject = data;
|
||||
for(const key of keys){
|
||||
if(!parentObject[key])
|
||||
parentObject[key] = {};
|
||||
parentObject = parentObject[key];
|
||||
}) => {
|
||||
const {
|
||||
stdout,
|
||||
stderr
|
||||
} = await exec(
|
||||
'whois',
|
||||
hostname
|
||||
);
|
||||
let data;
|
||||
switch(format){
|
||||
case 'text': {
|
||||
data = stdout;
|
||||
break;
|
||||
}
|
||||
case 'json':
|
||||
case 'nestedJson': {
|
||||
data = {};
|
||||
for(const line of stdout.split('\n')){
|
||||
const [, key, value] = line.match(/^\s*([\w\s]+)[^\w]?\s+(.+)$/) || [];
|
||||
if(key && value){
|
||||
if(format === 'json'){
|
||||
if(!data[key])
|
||||
data[key] = [];
|
||||
data[key].push(value);
|
||||
}
|
||||
else if(format === 'nestedJson'){
|
||||
const keys = key.split(/\s+/g);
|
||||
let parentObject = data;
|
||||
for(const key of keys){
|
||||
if(!parentObject[key])
|
||||
parentObject[key] = {};
|
||||
parentObject = parentObject[key];
|
||||
}
|
||||
if(!parentObject.$)
|
||||
parentObject.$ = [];
|
||||
parentObject.$.push(value);
|
||||
}
|
||||
if(!parentObject.$)
|
||||
parentObject.$ = [];
|
||||
parentObject.$.push(value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return {
|
||||
success: stdout && !stderr,
|
||||
data
|
||||
};
|
||||
}
|
||||
response.body = {
|
||||
success: stdout && !stderr,
|
||||
data
|
||||
};
|
||||
return response;
|
||||
}
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue