Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add cloudflare web3 gw support #255

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions md/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ for full access. If you prefer to use the **token**, it will need to have **read
zone access for all zones and DNS **editing** permissions for the specific zone
being updated.

To use the new Web3 Gateway feature set `IPFS_DEPLOY_CLOUDFLARE__USE_WEB3_GW` to `true`.
The **token** need to have **edit** permission on `Web3 Hostnames` for the specific zone.

- Usage: `-d cloudflare`
- Environment variables
- Credentials
Expand All @@ -226,6 +229,7 @@ being updated.
- Configuration
- `IPFS_DEPLOY_CLOUDFLARE__ZONE=<zone>`
- `IPFS_DEPLOY_CLOUDFLARE__RECORD=<record>`
- `IPFS_DEPLOY_CLOUDFLARE__USE_WEB3_GW=<0|true>`

#### Examples

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"dreamhost": "^1.0.5",
"files-from-path": "^0.2.6",
"form-data": "^4.0.0",
"got": "^11.8.2",
"ipfs-http-client": "^50.1.0",
"it-all": "^1.0.6",
"lodash.isempty": "^4.4.0",
Expand Down
3 changes: 2 additions & 1 deletion src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ const options = {
apiToken: argv.cloudflare && argv.cloudflare.apiToken,
apiEmail: argv.cloudflare && argv.cloudflare.apiEmail,
zone: argv.cloudflare && argv.cloudflare.zone,
record: argv.cloudflare && argv.cloudflare.record
record: argv.cloudflare && argv.cloudflare.record,
useWeb3Gw: argv.cloudflare && argv.cloudflare.useWeb3Gw
},
route53: {
accessKeyId: argv.route53 && argv.route53.accessKeyId,
Expand Down
80 changes: 77 additions & 3 deletions src/dnslinkers/cloudflare.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,78 @@
const dnslink = require('dnslink-cloudflare')
const isEmpty = require('lodash.isempty')

const got = require('got')
class CloudflareWeb3GatewayClient {
// @ts-ignore
async getZoneId (api, name) {
let res

for (let i = 1; (res = await api(`zones?page=${i}`)) && res.body.result_info.total_pages >= i; i++) {
for (const zone of res.body.result) {
if (zone.name === name) {
return zone.id
}
}
}

throw new Error(`zone ${name} couldn't be found`)
}

// https://api.cloudflare.com/#web3-hostname-list-web3-hostnames
// @ts-ignore
async getRecord (api, id, name) {
const res = await api(`zones/${id}/web3/hostnames`)

// @ts-ignore
const record = res.body.result.find(r => r.name === name)

return record
}

// @ts-ignore
getClient (apiOpts) {
const opts = {
prefixUrl: 'https://api.cloudflare.com/client/v4',
responseType: 'json'
}

if (apiOpts.token) {
// @ts-ignore
opts.headers = {
Authorization: `Bearer ${apiOpts.token}`
}
} else {
// @ts-ignore
opts.headers = {
'X-Auth-Email': apiOpts.email,
'X-Auth-Key': apiOpts.key
}
}

// @ts-ignore
return got.extend(opts)
}

// @ts-ignore
async update (apiOpts, { zone, link, record }) {
const api = this.getClient(apiOpts)
const id = await this.getZoneId(api, zone)
const rec = await this.getRecord(api, id, record)

if (!rec) {
throw new Error(`web3 gw for ${record} couldn't be found, must be created first`)
}

await api.patch(`zones/${id}/web3/hostnames/${rec.id}`, {
json: {
dnslink: link
}
})

return `dnslink=${link}`
}
}

/**
* @typedef {import('./types').DNSRecord} DNSRecord
* @typedef {import('./types').CloudflareOptions} CloudflareOptions
Expand All @@ -13,7 +85,7 @@ class Cloudflare {
/**
* @param {CloudflareOptions} options
*/
constructor ({ apiEmail, apiKey, apiToken, zone, record }) {
constructor ({ apiEmail, apiKey, apiToken, zone, record, useWeb3Gw }) {
if ([apiKey, apiEmail, apiToken].every(isEmpty)) {
throw new Error('apiEmail and apiKey or apiToken are required for Cloudflare')
}
Expand All @@ -31,7 +103,7 @@ class Cloudflare {
}
}

this.opts = { record, zone }
this.opts = { record, zone, useWeb3Gw: Boolean(useWeb3Gw) }
}

/**
Expand All @@ -44,7 +116,9 @@ class Cloudflare {
link: `/ipfs/${cid}`
}

const content = await dnslink(this.api, opts)
const content = this.opts.useWeb3Gw
? await (new CloudflareWeb3GatewayClient()).update(this.api, opts)
: await dnslink(this.api, opts)

return {
record: opts.record,
Expand Down
1 change: 1 addition & 0 deletions src/dnslinkers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface CloudflareOptions {
apiToken?: string
zone: string
record: string
useWeb3Gw?: boolean
}

export interface DNSimpleOptions {
Expand Down