diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index cc96ab9c1..66bfb9145 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -114,6 +114,7 @@ export default defineConfig({ {text: "连接windows主机", link: "/guide/use/host/windows.md"}, {text: "Google EAB获取", link: "/guide/use/google/"}, {text: "阿里云相关", link: "/guide/use/aliyun/"}, + {text: "Azure相关", link: "/guide/use/azure/dns.md"}, {text: "数据备份", link: "/guide/use/backup/"}, {text: "Certd本身的证书更新", link: "/guide/use/https/index.md"}, {text: "js脚本插件使用", link: "/guide/use/custom-script/index.md"}, diff --git a/docs/guide/use/azure/dns.md b/docs/guide/use/azure/dns.md new file mode 100644 index 000000000..0481fdcfb --- /dev/null +++ b/docs/guide/use/azure/dns.md @@ -0,0 +1,28 @@ +# Azure 配置 + +## Access授权配置 + +1. 登录 Azure 并创建一个资源组 【可选,如果已经有了可以不用创建】 +2. 创建一个应用程序 +Microsoft Entra ID - 》 应用注册 - 》 新注册 +![](./images/access-1.png) +![](./images/access-2.png) + +3. 配置授权 +![](./images/access-3.png) + +4. 点击测试 + +## Azure DNS 配置 + +1. 创建一个 DNS 区域(就是一个域名) +![](./images/dns-1.png) +![](./images/dns-2.png) + +2. 为这个域名和上面创建的授权应用分配角色 +![](./images/dns-3.png) +![](./images/dns-4.png) +![](./images/dns-5.png) + +3. 然后就可以给dns区域去申请证书了 + diff --git a/docs/guide/use/azure/images/access-1.png b/docs/guide/use/azure/images/access-1.png new file mode 100644 index 000000000..c27d5c09f Binary files /dev/null and b/docs/guide/use/azure/images/access-1.png differ diff --git a/docs/guide/use/azure/images/access-2.png b/docs/guide/use/azure/images/access-2.png new file mode 100644 index 000000000..452b4075e Binary files /dev/null and b/docs/guide/use/azure/images/access-2.png differ diff --git a/docs/guide/use/azure/images/access-3.png b/docs/guide/use/azure/images/access-3.png new file mode 100644 index 000000000..dba5ac7ee Binary files /dev/null and b/docs/guide/use/azure/images/access-3.png differ diff --git a/docs/guide/use/azure/images/dns-1.png b/docs/guide/use/azure/images/dns-1.png new file mode 100644 index 000000000..1229e22e3 Binary files /dev/null and b/docs/guide/use/azure/images/dns-1.png differ diff --git a/docs/guide/use/azure/images/dns-2.png b/docs/guide/use/azure/images/dns-2.png new file mode 100644 index 000000000..0a036ce56 Binary files /dev/null and b/docs/guide/use/azure/images/dns-2.png differ diff --git a/docs/guide/use/azure/images/dns-3.png b/docs/guide/use/azure/images/dns-3.png new file mode 100644 index 000000000..9eae6fc2e Binary files /dev/null and b/docs/guide/use/azure/images/dns-3.png differ diff --git a/docs/guide/use/azure/images/dns-4.png b/docs/guide/use/azure/images/dns-4.png new file mode 100644 index 000000000..e8e1d88d4 Binary files /dev/null and b/docs/guide/use/azure/images/dns-4.png differ diff --git a/docs/guide/use/azure/images/dns-5.png b/docs/guide/use/azure/images/dns-5.png new file mode 100644 index 000000000..503724b13 Binary files /dev/null and b/docs/guide/use/azure/images/dns-5.png differ diff --git a/packages/ui/certd-server/package.json b/packages/ui/certd-server/package.json index 52f81a912..9d1afcdde 100644 --- a/packages/ui/certd-server/package.json +++ b/packages/ui/certd-server/package.json @@ -37,6 +37,8 @@ "pub": "echo 1" }, "dependencies": { + "@azure/arm-dns": "^5.1.0", + "@azure/identity": "^4.13.1", "@alicloud/fc20230330": "^4.1.7", "@alicloud/openapi-client": "^0.4.12", "@alicloud/openapi-util": "^0.3.2", diff --git a/packages/ui/certd-server/src/plugins/plugin-azure/access.ts b/packages/ui/certd-server/src/plugins/plugin-azure/access.ts new file mode 100644 index 000000000..15216c864 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-azure/access.ts @@ -0,0 +1,268 @@ +import { AccessInput, BaseAccess, IsAccess } from '@certd/pipeline'; +import { DomainRecord } from '@certd/plugin-cert'; +import { utils } from '@certd/basic'; +import { PageRes, PageSearch } from '@certd/pipeline'; + +@IsAccess({ + name: 'azure', + title: '微软云Azure授权', + desc: '', + icon: 'simple-icons:microsoftazure', +}) +export class AzureAccess extends BaseAccess { + @AccessInput({ + title: '订阅 ID', + component: { + placeholder: 'subscriptionId', + }, + helper: 'Azure 订阅 ID', + required: true, + }) + subscriptionId = ''; + + + @AccessInput({ + title: '资源组', + component: { + placeholder: 'resourceGroupName', + }, + helper: 'DNS 区域所在的资源组名称', + required: true, + }) + resourceGroupName = ''; + + @AccessInput({ + title: '目录(租户) ID', + component: { + placeholder: 'tenantId', + }, + helper: '目录(租户) ID', + required: true, + }) + tenantId = ''; + + @AccessInput({ + title: '应用程序ID', + component: { + placeholder: 'clientId', + }, + helper: '应用程序(客户端) ID', + required: true, + }) + clientId = ''; + + @AccessInput({ + title: '客户端凭据', + component: { + placeholder: 'clientSecret', + }, + required: true, + encrypt: true, + helper: '客户端凭据(机密)->客户端密码->新客户端密码->时间选长一点的->复制值', + }) + clientSecret = ''; + + + + @AccessInput({ + title: "测试", + component: { + name: "api-test", + action: "TestRequest" + }, + helper: "测试授权是否正确" + }) + testRequest = true; + + async onTestRequest() { + this.ctx.logger.info('开始测试 Azure 认证...'); + + // 1. 先测试身份认证,获取访问令牌 + const { ClientSecretCredential } = await import('@azure/identity'); + + const credential = new ClientSecretCredential( + this.tenantId, + this.clientId, + this.clientSecret + ); + + // 获取 Azure 管理 API 的访问令牌来验证凭据 + this.ctx.logger.info('验证身份凭据...'); + const token = await credential.getToken('https://management.azure.com/.default'); + this.ctx.logger.info('身份认证成功!', token); + + return "ok"; + } + + async getDnsManagementClient() { + const { DnsManagementClient } = await import('@azure/arm-dns'); + const { ClientSecretCredential } = await import('@azure/identity'); + + const credential = new ClientSecretCredential( + this.tenantId, + this.clientId, + this.clientSecret + ); + + return new DnsManagementClient(credential, this.subscriptionId); + } + + async listZones(): Promise { + const client = await this.getDnsManagementClient(); + const zones: any[] = []; + + for await (const zone of client.zones.listByResourceGroup(this.resourceGroupName)) { + zones.push(zone); + } + + return zones; + } + + async getZoneId(domain: string): Promise<{ id: string; name: string }> { + const zones = await this.listZones(); + const domainSuffix = domain.endsWith('.') ? domain : domain + '.'; + + const matchingZone = zones.find((zone: any) => { + const zoneName = zone.name.endsWith('.') ? zone.name : zone.name + '.'; + return domainSuffix.endsWith(zoneName) || domainSuffix === zoneName; + }); + + if (!matchingZone) { + throw new Error(`找不到匹配的 DNS 区域: ${domain}`); + } + + this.ctx.logger.info(`找到 DNS 区域: ${matchingZone.name}, ID: ${matchingZone.id}`); + return { + id: matchingZone.id.split('/').pop()!, + name: matchingZone.name, + }; + } + + async listZonesPage(req: PageSearch): Promise> { + const zones = await this.listZones(); + let list = zones; + + if (req.searchKey) { + list = list.filter((zone: any) => zone.name.includes(req.searchKey)); + } + + list = list.map((item: any) => ({ + id: item.id.split('/').pop()!, + domain: item.name, + })); + + return { + total: list.length, + list, + }; + } + + + async createOrUpdateRecordSet(zoneName: string, recordType: string, relativeRecordSetName: string, value: string) { + const client = await this.getDnsManagementClient(); + + this.ctx.logger.info(`创建/更新记录集: ${relativeRecordSetName}.${zoneName}, 类型: ${recordType}, 值: ${value}`); + + // 获取现有记录集 + let existingRecordSet: any = null; + try { + existingRecordSet = await client.recordSets.get( + this.resourceGroupName, + zoneName, + relativeRecordSetName, + recordType as any + ); + } catch (e) { + // 记录集不存在,这是正常的 + } + + let txtRecords: any[] = []; + if (existingRecordSet && existingRecordSet.txtRecords) { + txtRecords = [...existingRecordSet.txtRecords]; + // 检查是否已存在相同的记录,避免重复 + const exists = txtRecords.some(r => r.value && r.value.includes(value)); + if (exists) { + this.ctx.logger.info(`记录值已存在,无需重复添加: ${value}`); + return existingRecordSet; + } + } + + // 添加新记录 + txtRecords.push({ + value: [value] + }); + + const recordSet = await client.recordSets.createOrUpdate( + this.resourceGroupName, + zoneName, + relativeRecordSetName, + recordType as any, + { + ttl: 60, + txtRecords: txtRecords + } + ); + + await utils.sleep(3000); + return recordSet; + } + + async deleteRecordSet(zoneName: string, recordType: string, relativeRecordSetName: string, value: string) { + const client = await this.getDnsManagementClient(); + + this.ctx.logger.info(`删除记录值: ${relativeRecordSetName}.${zoneName}, 类型: ${recordType}, 值: ${value}`); + + try { + // 获取现有记录集 + const existingRecordSet = await client.recordSets.get( + this.resourceGroupName, + zoneName, + relativeRecordSetName, + recordType as any + ); + + if (!existingRecordSet.txtRecords || existingRecordSet.txtRecords.length === 0) { + this.ctx.logger.info('记录集不存在或已为空,无需删除'); + return; + } + + // 过滤掉我们要删除的那个值 + const filteredTxtRecords = existingRecordSet.txtRecords.filter((r: any) => { + return !(r.value && r.value.includes(value)); + }); + + if (filteredTxtRecords.length === existingRecordSet.txtRecords.length) { + this.ctx.logger.info(`未找到要删除的记录值: ${value}`); + return; + } + + if (filteredTxtRecords.length === 0) { + // 如果没有记录了,就删除整个记录集 + this.ctx.logger.info('删除空记录集'); + await client.recordSets.delete( + this.resourceGroupName, + zoneName, + relativeRecordSetName, + recordType as any + ); + } else { + // 还有其他记录,只更新记录集,移除我们的值 + this.ctx.logger.info(`更新记录集,移除指定值,剩余 ${filteredTxtRecords.length} 条记录`); + await client.recordSets.createOrUpdate( + this.resourceGroupName, + zoneName, + relativeRecordSetName, + recordType as any, + { + ttl: existingRecordSet.ttl, + txtRecords: filteredTxtRecords + } + ); + } + } catch (e: any) { + this.ctx.logger.warn(`删除记录时出错: ${e.message}`); + } + } +} + +new AzureAccess(); diff --git a/packages/ui/certd-server/src/plugins/plugin-azure/azure-dns-provider.ts b/packages/ui/certd-server/src/plugins/plugin-azure/azure-dns-provider.ts new file mode 100644 index 000000000..366803569 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-azure/azure-dns-provider.ts @@ -0,0 +1,63 @@ +import { AbstractDnsProvider, CreateRecordOptions, DomainRecord, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert'; +import { AzureAccess } from './access.js'; +import { PageRes, PageSearch } from '@certd/pipeline'; + +@IsDnsProvider({ + name: 'azure-dns', + title: 'Azure DNS', + desc: 'Azure DNS 解析提供商', + accessType: 'azure', + icon: 'simple-icons:microsoftazure', + order: 1, +}) +export class AzureDnsProvider extends AbstractDnsProvider { + access: AzureAccess; + + async onInstance() { + this.access = this.ctx.access as AzureAccess; + } + + async createRecord(options: CreateRecordOptions): Promise { + const { fullRecord, value, type, domain } = options; + this.logger.info('添加域名解析:', fullRecord, value, type, domain); + + const zone = await this.access.getZoneId(domain); + this.logger.info(`获取到 DNS 区域: ${zone.name}, ID: ${zone.id}`); + + const relativeRecordSetName = fullRecord.replace(`.${zone.name}`, '').replace(`.${zone.name.replace(/\.$/, '')}`, ''); + + await this.access.createOrUpdateRecordSet(zone.name, type, relativeRecordSetName, value); + + return { + zoneId: zone.id, + zoneName: zone.name, + recordType: type, + relativeRecordSetName, + value: value, + }; + } + + async removeRecord(options: RemoveRecordOptions): Promise { + const { fullRecord, value: reqValue, type } = options.recordReq; + const record = options.recordRes; + + if (!record) { + this.logger.warn('记录信息为空,不执行删除'); + return; + } + + try { + const value = record.value || reqValue; + await this.access.deleteRecordSet(record.zoneName, record.recordType, record.relativeRecordSetName, value); + this.logger.info(`删除域名解析成功:${fullRecord} ${value} ${type}`); + } catch (e: any) { + this.logger.warn(`删除域名解析失败:${e.message}`, ); + } + } + + async getDomainListPage(req: PageSearch): Promise> { + return await this.access.listZonesPage(req); + } +} + +new AzureDnsProvider(); diff --git a/packages/ui/certd-server/src/plugins/plugin-azure/index.ts b/packages/ui/certd-server/src/plugins/plugin-azure/index.ts new file mode 100644 index 000000000..91f51fd00 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-azure/index.ts @@ -0,0 +1,2 @@ +export * from './access.js'; +export * from './azure-dns-provider.js'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 614952812..b86e3f9b5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1446,6 +1446,12 @@ importers: '@aws-sdk/client-sts': specifier: ^3.990.0 version: 3.990.0(aws-crt@1.26.2) + '@azure/arm-dns': + specifier: ^5.1.0 + version: 5.1.0 + '@azure/identity': + specifier: ^4.13.1 + version: 4.13.1 '@certd/acme-client': specifier: ^1.39.10 version: link:../../core/acme-client @@ -2278,6 +2284,66 @@ packages: resolution: {integrity: sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg==} engines: {node: '>=18.0.0'} + '@azure/abort-controller@1.1.0': + resolution: {integrity: sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==} + engines: {node: '>=12.0.0'} + + '@azure/abort-controller@2.1.2': + resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} + engines: {node: '>=18.0.0'} + + '@azure/arm-dns@5.1.0': + resolution: {integrity: sha512-zEh1FZ6sctbtll11FuxyPl2CBo1PT9iGUuZGXQVSkg+9b3CcLatKQN6ZOZZWugFi86y3EZERIE4IjY5r7vD7Bg==} + engines: {node: '>=14.0.0'} + + '@azure/core-auth@1.10.1': + resolution: {integrity: sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==} + engines: {node: '>=20.0.0'} + + '@azure/core-client@1.10.1': + resolution: {integrity: sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==} + engines: {node: '>=20.0.0'} + + '@azure/core-lro@2.7.2': + resolution: {integrity: sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==} + engines: {node: '>=18.0.0'} + + '@azure/core-paging@1.6.2': + resolution: {integrity: sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==} + engines: {node: '>=18.0.0'} + + '@azure/core-rest-pipeline@1.23.0': + resolution: {integrity: sha512-Evs1INHo+jUjwHi1T6SG6Ua/LHOQBCLuKEEE6efIpt4ZOoNonaT1kP32GoOcdNDbfqsD2445CPri3MubBy5DEQ==} + engines: {node: '>=20.0.0'} + + '@azure/core-tracing@1.3.1': + resolution: {integrity: sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==} + engines: {node: '>=20.0.0'} + + '@azure/core-util@1.13.1': + resolution: {integrity: sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==} + engines: {node: '>=20.0.0'} + + '@azure/identity@4.13.1': + resolution: {integrity: sha512-5C/2WD5Vb1lHnZS16dNQRPMjN6oV/Upba+C9nBIs15PmOi6A3ZGs4Lr2u60zw4S04gi+u3cEXiqTVP7M4Pz3kw==} + engines: {node: '>=20.0.0'} + + '@azure/logger@1.3.0': + resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} + engines: {node: '>=20.0.0'} + + '@azure/msal-browser@5.8.0': + resolution: {integrity: sha512-X7IZV77bN56l7sbLjkcbQJX1t3U4tgxqztDr/XFbUcUfKk+z2FavcLgKP+OYUNj0wl/pEEtV9lldW9siY8BuHQ==} + engines: {node: '>=0.8.0'} + + '@azure/msal-common@16.5.1': + resolution: {integrity: sha512-WS9w9SfI8SEYO7mTnxGeZ3UwQfhAVYCWglYF2/7GNx3ioHiAs2gPkl9eSwVs8cPrmiGh+zi9ai/OOKoq4cyzDw==} + engines: {node: '>=0.8.0'} + + '@azure/msal-node@5.1.4': + resolution: {integrity: sha512-G4LXGGggok1QC48uKu64/SV2DPRDlddmV8EieK8pflsNYMj9/Zz+Y9OHoEBhT15h+zpdwXXLYA/7PJCR/yZ8aw==} + engines: {node: '>=20'} + '@babel/code-frame@7.12.11': resolution: {integrity: sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==} @@ -5235,6 +5301,10 @@ packages: resolution: {integrity: sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typespec/ts-http-runtime@0.3.5': + resolution: {integrity: sha512-yURCknZhvywvQItHMMmFSo+fq5arCUIyz/CVk7jD89MSai7dkaX8ufjCWp3NttLojoTVbcE72ri+be/TnEbMHw==} + engines: {node: '>=20.0.0'} + '@ucloud-sdks/ucloud-sdk-js@0.2.4': resolution: {integrity: sha512-jAE8IEagtLXoj172/YMmwnMHDH+DlwgvSmMYtEge618oa/Wkn1BwSofRAx1r5afjBkDGLRdGN9+X+53Y+akqag==} @@ -6092,6 +6162,10 @@ packages: builtin-status-codes@3.0.0: resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + byline@5.0.0: resolution: {integrity: sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==} engines: {node: '>=0.10.0'} @@ -6950,6 +7024,14 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + engines: {node: '>=18'} + default-user-agent@1.0.0: resolution: {integrity: sha512-bDF7bg6OSNcSwFWPu4zYKpVkJZQYVrAANMYB8bc9Szem1D0yKdm4sa/rOCs2aC9+2GMqQ7KnwtZRvDhmLF0dXw==} engines: {node: '>= 0.10.0'} @@ -6968,6 +7050,10 @@ packages: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -8437,6 +8523,11 @@ packages: engines: {node: '>=8'} hasBin: true + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -8468,6 +8559,11 @@ packages: is-hotkey@0.2.0: resolution: {integrity: sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==} + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + is-installed-globally@0.4.0: resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} engines: {node: '>=10'} @@ -8623,6 +8719,10 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + is-yarn-global@0.3.0: resolution: {integrity: sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==} @@ -9906,6 +10006,10 @@ packages: only@0.0.2: resolution: {integrity: sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==} + open@10.2.0: + resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} + engines: {node: '>=18'} + open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} @@ -11204,6 +11308,10 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} @@ -12937,6 +13045,10 @@ packages: utf-8-validate: optional: true + wsl-utils@0.1.0: + resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} + engines: {node: '>=18'} + xdg-basedir@4.0.0: resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==} engines: {node: '>=8'} @@ -14498,6 +14610,118 @@ snapshots: '@aws/lambda-invoke-store@0.2.2': {} + '@azure/abort-controller@1.1.0': + dependencies: + tslib: 2.8.1 + + '@azure/abort-controller@2.1.2': + dependencies: + tslib: 2.8.1 + + '@azure/arm-dns@5.1.0': + dependencies: + '@azure/abort-controller': 1.1.0 + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.1 + '@azure/core-lro': 2.7.2 + '@azure/core-paging': 1.6.2 + '@azure/core-rest-pipeline': 1.23.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-auth@1.10.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-client@1.10.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-rest-pipeline': 1.23.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-lro@2.7.2': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-paging@1.6.2': + dependencies: + tslib: 2.8.1 + + '@azure/core-rest-pipeline@1.23.0': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + '@typespec/ts-http-runtime': 0.3.5 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-tracing@1.3.1': + dependencies: + tslib: 2.8.1 + + '@azure/core-util@1.13.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@typespec/ts-http-runtime': 0.3.5 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/identity@4.13.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.1 + '@azure/core-rest-pipeline': 1.23.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + '@azure/msal-browser': 5.8.0 + '@azure/msal-node': 5.1.4 + open: 10.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/logger@1.3.0': + dependencies: + '@typespec/ts-http-runtime': 0.3.5 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/msal-browser@5.8.0': + dependencies: + '@azure/msal-common': 16.5.1 + + '@azure/msal-common@16.5.1': {} + + '@azure/msal-node@5.1.4': + dependencies: + '@azure/msal-common': 16.5.1 + jsonwebtoken: 9.0.2 + uuid: 8.3.2 + '@babel/code-frame@7.12.11': dependencies: '@babel/highlight': 7.25.9 @@ -18319,6 +18543,14 @@ snapshots: '@typescript-eslint/types': 8.32.1 eslint-visitor-keys: 4.2.0 + '@typespec/ts-http-runtime@0.3.5': + dependencies: + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + '@ucloud-sdks/ucloud-sdk-js@0.2.4': dependencies: axios: 0.21.4(debug@4.4.3) @@ -19477,6 +19709,10 @@ snapshots: builtin-status-codes@3.0.0: {} + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + byline@5.0.0: {} byte-size@9.0.1: {} @@ -20385,6 +20621,13 @@ snapshots: deepmerge@4.3.1: {} + default-browser-id@5.0.1: {} + + default-browser@5.5.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + default-user-agent@1.0.0: dependencies: os-name: 1.0.3 @@ -20403,6 +20646,8 @@ snapshots: define-lazy-prop@2.0.0: {} + define-lazy-prop@3.0.0: {} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 @@ -20997,13 +21242,13 @@ snapshots: resolve: 1.22.10 semver: 6.3.1 - eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8): + eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8): dependencies: eslint: 7.32.0 prettier: 2.8.8 prettier-linter-helpers: 1.0.0 optionalDependencies: - eslint-config-prettier: 8.10.0(eslint@7.32.0) + eslint-config-prettier: 8.10.0(eslint@8.57.0) eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8): dependencies: @@ -22241,6 +22486,8 @@ snapshots: is-docker@2.2.1: {} + is-docker@3.0.0: {} + is-extendable@0.1.1: {} is-extglob@2.1.1: {} @@ -22266,6 +22513,10 @@ snapshots: is-hotkey@0.2.0: {} + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + is-installed-globally@0.4.0: dependencies: global-dirs: 3.0.1 @@ -22392,6 +22643,10 @@ snapshots: dependencies: is-docker: 2.2.1 + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + is-yarn-global@0.3.0: {} isarray@0.0.1: {} @@ -23478,7 +23733,7 @@ snapshots: eslint: 7.32.0 eslint-config-prettier: 8.10.0(eslint@7.32.0) eslint-plugin-node: 11.1.0(eslint@7.32.0) - eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8) + eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8) execa: 5.1.1 inquirer: 7.3.3 json5: 2.2.3 @@ -23817,6 +24072,13 @@ snapshots: only@0.0.2: {} + open@10.2.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + wsl-utils: 0.1.0 + open@8.4.2: dependencies: define-lazy-prop: 2.0.0 @@ -25258,6 +25520,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.50.0 fsevents: 2.3.3 + run-applescript@7.1.0: {} + run-async@2.4.1: {} run-parallel@1.2.0: @@ -27167,6 +27431,10 @@ snapshots: ws@8.18.2: {} + wsl-utils@0.1.0: + dependencies: + is-wsl: 3.1.1 + xdg-basedir@4.0.0: {} xlsx@0.18.5: