Skip to content

Commit

Permalink
Merge pull request #36 from XYOracleNetwork/feature/xns-dns-types
Browse files Browse the repository at this point in the history
XNS DNS Types
  • Loading branch information
JoelBCarter authored Aug 26, 2024
2 parents 37a428d + c7a20af commit 6f61ea1
Show file tree
Hide file tree
Showing 21 changed files with 689 additions and 1 deletion.
4 changes: 3 additions & 1 deletion packages/payload/packages/xns/plugins/record/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
"@xylabs/hex": "^4.0.5",
"@xyo-network/boundwitness-model": "^3.0.11",
"@xyo-network/boundwitness-validator": "^3.0.11",
"@xyo-network/module-model": "^3.0.13",
"@xyo-network/payload-builder": "^3.0.11",
"@xyo-network/payload-model": "^3.0.11"
"@xyo-network/payload-model": "^3.0.11",
"@xyo-network/witness-model": "^3.0.13"
},
"devDependencies": {
"@xylabs/ts-scripts-yarn3": "^4.0.7",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { ModuleIdentifier } from '@xyo-network/module-model'
import type { WitnessConfig } from '@xyo-network/witness-model'

import type { DNSResourceRecordType } from '../types/index.ts'
import { DNSSchema } from './Schema.ts'

export type DNSWitnessConfigSchema = `${DNSSchema}.witness.config`
export const DNSWitnessConfigSchema: DNSWitnessConfigSchema = `${DNSSchema}.witness.config`

export type DNSWitnessConfig = WitnessConfig<{
/**
* The domain lease registrant diviner to be used to determine the domain lease registrant
* for XNS domains
*/
domainLeaseRegistrantDiviner?: ModuleIdentifier
/**
* The config schema for the DNS witness
*/
schema: DNSWitnessConfigSchema
/**
* If supplied, the DNS witness will only support the specified resource record types
*/
supportedResources?: DNSResourceRecordType[]
}>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { AnyConfigSchema } from '@xyo-network/module-model'
import type { WitnessParams } from '@xyo-network/witness-model'

import type { DNSWitnessConfig } from './Config.ts'

export type DNSWitnessParams = WitnessParams<AnyConfigSchema<DNSWitnessConfig>>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import type { DNSRequest } from './Request.ts'
import type { DNSResponse } from './Response.ts'

export type DNS = DNSRequest | DNSResponse
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { PayloadWithSources } from '@xyo-network/payload-model'
import {
isPayloadOfSchemaType,
isPayloadOfSchemaTypeWithMeta,
isPayloadOfSchemaTypeWithSources,
} from '@xyo-network/payload-model'

import type { DNSRequestFields, DNSResourceRecordTypeValue } from '../../types/index.ts'
import { DNSResourceRecordTypes, getRequestFor } from '../../types/index.ts'
import { DNSSchema } from '../Schema.ts'

/**
* The fields of a DNSRequest payload
*/
export type DNSRequest = PayloadWithSources<DNSRequestFields, DNSSchema>

/**
* Identity function for determining if an object is a DNSRequest payload
*/
export const isDNSRequest = isPayloadOfSchemaType<DNSRequest>(DNSSchema)

/**
* Identity function for determining if an object is a DNSRequest payload with sources
*/
export const isDNSRequestWithSources = isPayloadOfSchemaTypeWithSources<DNSRequest>(DNSSchema)

/**
* Identity function for determining if an object is a DNSRequest payload with meta
*/
export const isDNSRequestWithMeta = isPayloadOfSchemaTypeWithMeta<DNSRequest>(DNSSchema)

/**
* Helper for generating a DNSRequest payload for a given domain and record type
* @param domain The domain to query
* @param type The record type to query
* @returns A DNSRequest payload
*/
export const getDnsRequestFor = (domain: string, type: DNSResourceRecordTypeValue = DNSResourceRecordTypes.A): DNSRequest => {
return { ...getRequestFor(domain, type), schema: DNSSchema }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { PayloadWithSources } from '@xyo-network/payload-model'
import {
isPayloadOfSchemaType,
isPayloadOfSchemaTypeWithMeta,
isPayloadOfSchemaTypeWithSources,
} from '@xyo-network/payload-model'

import type { DNSResponseFields } from '../../types/index.ts'
import { DNSSchema } from '../Schema.ts'

/**
* The fields of a DNSResponse payload
*/
export type DNSResponse = PayloadWithSources<DNSResponseFields, DNSSchema>

/**
* Identity function for determining if an object is a DNSResponse payload
*/
export const isDNSResponse = isPayloadOfSchemaType<DNSResponse>(DNSSchema)

/**
* Identity function for determining if an object is a DNSResponse payload with sources
*/
export const isDNSResponseWithSources = isPayloadOfSchemaTypeWithSources<DNSResponse>(DNSSchema)

/**
* Identity function for determining if an object is a DNSResponse payload with meta
*/
export const isDNSResponseWithMeta = isPayloadOfSchemaTypeWithMeta<DNSResponse>(DNSSchema)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './Payload.ts'
export * from './Request.ts'
export * from './Response.ts'
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export type DNSSchema = 'network.xyo.dns'
export const DNSSchema: DNSSchema = 'network.xyo.dns'
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './Config.ts'
export * from './Payload/index.ts'
export * from './Schema.ts'
2 changes: 2 additions & 0 deletions packages/payload/packages/xns/plugins/record/src/DNS/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './types/index.ts'
export * from './Witness/index.ts'
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { DNSRecord } from './Record.ts'

export interface DNSAnswer extends DNSRecord {
class?: number // The class (typically 1 for IN - Internet)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* eslint-disable @typescript-eslint/member-ordering */

// An attempt to match compatibility with the RFC 8427 (Representing DNS Messages in JSON)
// https://www.rfc-editor.org/rfc/rfc8427
// and Google/CloudFlare's DNS over HTTPS (DoH) standard
// https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/make-api-requests/dns-json/

import { type DNSQueryOpcode, DNSQueryOpcodes } from './OperationCodes.ts'
import type { DNSRcode } from './ResponseCodes.ts'
import { DNSRcodes } from './ResponseCodes.ts'

// NOTE: The RFC says `Boolean` but uses 0/1 for the values. DNS over HTTPS (DoH) uses `true`/`false`.
export type NumericBoolean = 0 | 1 | true | false
export type NumericBooleanFalsy = 0 | false
export type NumericBooleanTruthy = 1 | true

export interface DNSHeader {
/**
* Transaction ID, typically a random number. Integer whose value is 0 to 65535
*/
ID?: number
/**
* Query/Response Flag (0 = Query, 1 = Response)
*/
QR?: NumericBoolean
/**
* Operation Code (0 for standard query)
*/
Opcode?: DNSQueryOpcode
/**
* Authoritative Answer (set in response)
*/
AA?: NumericBoolean
/**
* Truncated Flag
*/
TC?: NumericBoolean // Truncation
/**
* Recursion Desired
*/
RD?: NumericBoolean // Recursion Desired (set in query)
/**
* Response Code (0 for no error, non-0 for errors)
*/
RCODE?: DNSRcode
/**
* Number of questions in the query (usually 1)
*/
QDCOUNT?: number
/**
* Number of answer records in the response
*/
ANCOUNT?: number
/**
* Number of authority records in the response
*/
NSCOUNT?: number
/**
* Number of additional records in the response
*/
ARCOUNT?: number
}

export interface DNSRequestHeader extends DNSHeader {
QR: NumericBooleanFalsy // Query/Response Flag (0 = Query)
Opcode: DNSQueryOpcode // Operation Code (0 for standard query)
AA: NumericBooleanFalsy // Authoritative Answer (0 in query)
TC: NumericBooleanFalsy // Truncation (0 for non-truncated)
RCODE: typeof DNSRcodes.NOERROR // Response Code (always 0 in query)
ANCOUNT: 0 // Number of answer records (always 0 in query)
NSCOUNT: 0 // Number of authority records (always 0 in query)
ARCOUNT: 0 // Number of additional records (always 0 in query)
}

export const StandardRequestHeader: Readonly<DNSRequestHeader> = {
ID: 0,
QR: 0, // Query/Response Flag (0 = Query)
Opcode: DNSQueryOpcodes.QUERY, // Operation Code (0 for standard query)
AA: 0, // Authoritative Answer (0 in query)
TC: 0, // Truncation (0 for non-truncated)
RD: 1, // Recursion Desired (1 if recursion is requested)
RCODE: DNSRcodes.NOERROR, // Response Code (always 0 in query)
QDCOUNT: 1,
ANCOUNT: 0,
NSCOUNT: 0,
ARCOUNT: 0,
}

export interface DNSResponseHeader extends DNSHeader {
QR: NumericBooleanTruthy // Query/Response Flag (1 = Response)
Opcode: DNSQueryOpcode // Operation Code (0 for standard query)
AA: NumericBoolean // Authoritative Answer (1 if the response is authoritative)
TC: NumericBoolean // Truncation (1 if the message is truncated)
RA: NumericBoolean // Recursion Available (1 if the server supports recursion)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export type DNSQueryOpcode = 0 | 1 | 2 | 4 | 5 | 6 // Supported opcodes as numeric values

// Optional: Add a more descriptive union type for the opcodes.
export type DNSQueryOpcodeName = 'QUERY' | 'IQUERY' | 'STATUS' | 'NOTIFY' | 'UPDATE' | 'DSO'

export const DNSQueryOpcodes: Record<DNSQueryOpcodeName, DNSQueryOpcode> = {
QUERY: 0,
IQUERY: 1,
STATUS: 2,
NOTIFY: 4,
UPDATE: 5,
DSO: 6,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* eslint-disable @typescript-eslint/member-ordering */
import type { DNSResourceRecordTypeValue } from './ResourceRecord.ts'

export interface DNSRecord {
name: string // The domain name that was queried
type: DNSResourceRecordTypeValue // The record type (e.g., 1 for A record)
TTL: number // Time to Live (how long the record can be cached)
data: string // The actual data, such as an IP address or TXT record
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* eslint-disable @typescript-eslint/member-ordering */
import { type DNSRequestHeader, StandardRequestHeader } from './Header.ts'
import type { DNSResourceRecordTypeValue } from './ResourceRecord.ts'
import { DNSResourceRecordTypes } from './ResourceRecord.ts'

export interface DNSQuestion {
name: string // The domain name that was queried
type: DNSResourceRecordTypeValue // The record type (e.g., 1 for A record)
class?: number // Query Class (typically 1 for IN - Internet)
}

export interface DNSRequestFields extends DNSRequestHeader {
Question: DNSQuestion[]
}

/**
* Helper for generating a DNS request for a given domain and record type
* @param domain The domain to query
* @param type The record type to query
* @returns A DNS request
*/
export const getRequestFor = (domain: string, type: DNSResourceRecordTypeValue = DNSResourceRecordTypes.A): DNSRequestFields => {
return {
...StandardRequestHeader,
ID: getRandomId(),
Question: [{
name: domain, type, class: 1,
}],
}
}

/**
* Used to generate a random ID for a DNS request
* @returns A random number between 0 and 65,535
*/
export const getRandomId = (): number => {
return Math.floor(Math.random() * 65_536) // Math.random() generates a number between 0 and 1, multiply by 65536 to get the range 0-65535
}
Loading

0 comments on commit 6f61ea1

Please sign in to comment.