mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-05 23:26:38 +08:00
feat(cloudflare): add DNS pointing integration
Implement Cloudflare connection management, pointing groups and members, asynchronous A-record reconciliation, node IP triggers, admin APIs, management pages, migrations, tests, and documentation.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import { OpenFlareBaseService } from './base.service';
|
||||
import type {
|
||||
CloudflareAvailableDomain,
|
||||
CloudflareConnection,
|
||||
CloudflareConnectionPayload,
|
||||
CloudflareGroup,
|
||||
CloudflareGroupDetail,
|
||||
CloudflareGroupPayload,
|
||||
CloudflareMember,
|
||||
CloudflareMemberCreatePayload,
|
||||
CloudflareOverview,
|
||||
CloudflareSyncReceipt,
|
||||
} from './types';
|
||||
|
||||
export const cloudflareQueryKey = ['openflare', 'cloudflare'] as const;
|
||||
|
||||
export class CloudflareService extends OpenFlareBaseService {
|
||||
protected static override readonly basePath = '/api/v1/d/cloudflare';
|
||||
|
||||
static getConnection(): Promise<CloudflareConnection> {
|
||||
return this.get<CloudflareConnection>('/connection');
|
||||
}
|
||||
|
||||
static saveConnection(
|
||||
payload: CloudflareConnectionPayload,
|
||||
): Promise<CloudflareConnection> {
|
||||
return this.put<CloudflareConnection>('/connection', payload);
|
||||
}
|
||||
|
||||
static verifyConnection(): Promise<CloudflareConnection> {
|
||||
return this.post<CloudflareConnection>('/connection/verify');
|
||||
}
|
||||
|
||||
static clearConnection(): Promise<void> {
|
||||
return this.post<void>('/connection/clear');
|
||||
}
|
||||
|
||||
static getOverview(): Promise<CloudflareOverview> {
|
||||
return this.get<CloudflareOverview>('/overview');
|
||||
}
|
||||
|
||||
static listGroups(): Promise<CloudflareGroup[]> {
|
||||
return this.get<CloudflareGroup[]>('/groups');
|
||||
}
|
||||
|
||||
static getGroup(id: number): Promise<CloudflareGroupDetail> {
|
||||
return this.get<CloudflareGroupDetail>(`/groups/${id}`);
|
||||
}
|
||||
|
||||
static createGroup(
|
||||
payload: CloudflareGroupPayload,
|
||||
): Promise<CloudflareGroup> {
|
||||
return this.post<CloudflareGroup>('/groups', payload);
|
||||
}
|
||||
|
||||
static updateGroup(
|
||||
id: number,
|
||||
payload: CloudflareGroupPayload,
|
||||
): Promise<CloudflareGroup> {
|
||||
return this.post<CloudflareGroup>(`/groups/${id}/update`, payload);
|
||||
}
|
||||
|
||||
static deleteGroup(id: number): Promise<void> {
|
||||
return this.post<void>(`/groups/${id}/delete`);
|
||||
}
|
||||
|
||||
static syncGroup(id: number): Promise<CloudflareSyncReceipt> {
|
||||
return this.post<CloudflareSyncReceipt>(`/groups/${id}/sync`);
|
||||
}
|
||||
|
||||
static listAvailableDomains(): Promise<CloudflareAvailableDomain[]> {
|
||||
return this.get<CloudflareAvailableDomain[]>('/domains/available');
|
||||
}
|
||||
|
||||
static createMember(
|
||||
groupId: number,
|
||||
payload: CloudflareMemberCreatePayload,
|
||||
): Promise<CloudflareMember> {
|
||||
return this.post<CloudflareMember>(`/groups/${groupId}/members`, payload);
|
||||
}
|
||||
|
||||
static updateMember(
|
||||
groupId: number,
|
||||
memberId: number,
|
||||
proxied: boolean,
|
||||
): Promise<CloudflareMember> {
|
||||
return this.post<CloudflareMember>(
|
||||
`/groups/${groupId}/members/${memberId}/update`,
|
||||
{ proxied },
|
||||
);
|
||||
}
|
||||
|
||||
static removeMember(groupId: number, memberId: number): Promise<void> {
|
||||
return this.post<void>(`/groups/${groupId}/members/${memberId}/remove`);
|
||||
}
|
||||
|
||||
static syncMember(
|
||||
groupId: number,
|
||||
memberId: number,
|
||||
): Promise<CloudflareSyncReceipt> {
|
||||
return this.post<CloudflareSyncReceipt>(
|
||||
`/groups/${groupId}/members/${memberId}/sync`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,10 @@ export { AccessLogService } from './access-log.service';
|
||||
export { OptionService } from './option.service';
|
||||
export { UptimeKumaService } from './uptimekuma.service';
|
||||
export { StatusService } from './status.service';
|
||||
export {
|
||||
CloudflareService,
|
||||
cloudflareQueryKey,
|
||||
} from './cloudflare.service';
|
||||
|
||||
export type {
|
||||
ApplyLogCleanupPayload,
|
||||
@@ -143,6 +147,19 @@ export type {
|
||||
TlsCertificateFileImportPayload,
|
||||
TlsCertificateItem,
|
||||
TlsCertificateMutationPayload,
|
||||
CloudflareAvailableDomain,
|
||||
CloudflareConnection,
|
||||
CloudflareConnectionPayload,
|
||||
CloudflareConnectionSource,
|
||||
CloudflareGroup,
|
||||
CloudflareGroupDetail,
|
||||
CloudflareGroupPayload,
|
||||
CloudflareMember,
|
||||
CloudflareMemberCreatePayload,
|
||||
CloudflareNodeOption,
|
||||
CloudflareOverview,
|
||||
CloudflareSyncReceipt,
|
||||
CloudflareSyncStatus,
|
||||
} from './types';
|
||||
|
||||
import { AccessLogService } from './access-log.service';
|
||||
@@ -160,6 +177,7 @@ import { ProxyRouteService } from './proxy-route.service';
|
||||
import { TlsCertificateService } from './tls-certificate.service';
|
||||
import { WafService } from './waf.service';
|
||||
import { ZoneDomainService, ZoneService } from './zone.service';
|
||||
import { CloudflareService } from './cloudflare.service';
|
||||
|
||||
export const openflareServices = {
|
||||
node: NodeService,
|
||||
@@ -178,4 +196,5 @@ export const openflareServices = {
|
||||
option: OptionService,
|
||||
uptimeKuma: UptimeKumaService,
|
||||
status: StatusService,
|
||||
cloudflare: CloudflareService,
|
||||
} as const;
|
||||
|
||||
@@ -1347,6 +1347,93 @@ export interface ZoneStats {
|
||||
series: ZoneStatsPoint[];
|
||||
}
|
||||
|
||||
export type CloudflareConnectionSource = 'dns_account' | 'standalone';
|
||||
export type CloudflareSyncStatus = 'pending' | 'syncing' | 'ok' | 'error';
|
||||
|
||||
export interface CloudflareConnection {
|
||||
configured: boolean;
|
||||
ready: boolean;
|
||||
source: CloudflareConnectionSource | '';
|
||||
dns_account_id: number | null;
|
||||
status: string;
|
||||
verified_at: string | null;
|
||||
}
|
||||
|
||||
export interface CloudflareConnectionPayload {
|
||||
source: CloudflareConnectionSource;
|
||||
dns_account_id: number;
|
||||
api_token: string;
|
||||
}
|
||||
|
||||
export interface CloudflareNodeOption {
|
||||
id: number;
|
||||
name: string;
|
||||
ip: string;
|
||||
}
|
||||
|
||||
export interface CloudflareGroup {
|
||||
id: number;
|
||||
name: string;
|
||||
primary_node: CloudflareNodeOption;
|
||||
backup_node: CloudflareNodeOption | null;
|
||||
active_node: CloudflareNodeOption;
|
||||
default_proxied: boolean;
|
||||
enabled: boolean;
|
||||
member_count: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface CloudflareGroupPayload {
|
||||
name: string;
|
||||
primary_node_id: number;
|
||||
backup_node_id: number | null;
|
||||
default_proxied: boolean;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface CloudflareMember {
|
||||
id: number;
|
||||
group_id: number;
|
||||
zone_domain_id: number;
|
||||
domain: string;
|
||||
zone_id: number;
|
||||
proxied: boolean;
|
||||
desired_ip: string;
|
||||
sync_status: CloudflareSyncStatus;
|
||||
last_error: string;
|
||||
synced_at: string | null;
|
||||
}
|
||||
|
||||
export interface CloudflareMemberCreatePayload {
|
||||
zone_domain_id: number;
|
||||
proxied?: boolean;
|
||||
}
|
||||
|
||||
export interface CloudflareGroupDetail {
|
||||
group: CloudflareGroup;
|
||||
members: CloudflareMember[];
|
||||
}
|
||||
|
||||
export interface CloudflareAvailableDomain {
|
||||
id: number;
|
||||
zone_id: number;
|
||||
domain: string;
|
||||
}
|
||||
|
||||
export interface CloudflareOverview {
|
||||
connection: CloudflareConnection;
|
||||
group_count: number;
|
||||
member_count: number;
|
||||
ok_count: number;
|
||||
pending_count: number;
|
||||
error_count: number;
|
||||
}
|
||||
|
||||
export interface CloudflareSyncReceipt {
|
||||
task_id: string;
|
||||
}
|
||||
|
||||
export interface TlsCertificateItem {
|
||||
id: number;
|
||||
name: string;
|
||||
|
||||
Reference in New Issue
Block a user