'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var hapic = require('hapic'); var smob = require('smob'); /* * Copyright (c) 2023. * Author Peter Placzek (tada5hi) * For the full copyright and license information, * view the LICENSE file that was distributed with this source code. */ var HeaderName = /*#__PURE__*/ function(HeaderName) { HeaderName["LOCATION"] = "location"; HeaderName["IS_RESOURCE_NAME"] = "X-Is-Resource-Name"; HeaderName["TOTAL_COUNT"] = "X-Total-Count"; return HeaderName; }({}); /* * Copyright (c) 2021-2021. * Author Peter Placzek (tada5hi) * For the full copyright and license information, * view the LICENSE file that was distributed with this source code. */ class ConnectionStringParseError extends Error { static connectionStringMissing(serviceName) { const parts = [ 'The' ]; if (typeof serviceName === 'string') { parts.push(serviceName); } parts.push('connection string is not specified.'); return new this(parts.join(' ')); } static connectionStringInvalid(serviceName) { const parts = [ 'The' ]; if (typeof serviceName === 'string') { parts.push(serviceName); } parts.push('connection string is not valid.'); return new this(parts.join(' ')); } } function parseConnectionString(connectionString) { const parts = connectionString.split('@'); if (parts.length !== 2) { throw new ConnectionStringParseError('Harbor connection string must be in the following format: user:password@host'); } const host = parts[1]; const authParts = parts[0].split(':'); if (authParts.length !== 2) { throw new ConnectionStringParseError('Harbor connection string must be in the following format: user:password@host'); } return { host, user: authParts[0], password: authParts[1] }; } function buildQueryString(input, withQuestionMark = true) { if (typeof input === 'undefined') { return ''; } const searchParams = new URLSearchParams(); const keys = Object.keys(input); for(let i = 0; i < keys.length; i++){ const value = input[keys[i]]; if (smob.isObject(value)) { const childKeys = Object.keys(value); if (childKeys.length > 0) { const childSearchParams = new URLSearchParams(); for(let j = 0; j < childKeys.length; j++){ childSearchParams.append(childKeys[j], `${encodeURIComponent(value[childKeys[j]])}`); } searchParams.append(keys[i], childSearchParams.toString()); } } else if (Array.isArray(value)) { searchParams.append(keys[i], `${value.join(',')}`); } else { searchParams.append(keys[i], `${value}`); } } const queryString = searchParams.toString(); if (queryString.length > 0 && withQuestionMark) { return `?${queryString}`; } return ''; } function extractResourceIDOfResponse(response) { if (response && response.headers && response.headers.has(HeaderName.LOCATION)) { const value = response.headers.get(HeaderName.LOCATION); if (value) { const id = parseInt(value.substring(value.lastIndexOf('/') + 1), 10); if (!Number.isNaN(id)) { return id; } } } return undefined; } function extractResourceMetaOfResponse(response) { const meta = {}; if (response.headers && response.headers.has(HeaderName.TOTAL_COUNT)) { const total = parseInt(response.headers.get(HeaderName.TOTAL_COUNT) || '0', 10); if (!Number.isNaN(total)) { meta.total = total; } } return meta; } class BaseAPI { // ----------------------------------------------------------------------------------- setClient(input) { if (hapic.isClient(input)) { this.client = input; } else { this.client = hapic.createClient(input); } } // ----------------------------------------------------------------------------------- constructor(context){ context = context || {}; this.setClient(context.client); } } class ProjectAPI extends BaseAPI { async create(data) { const response = await this.client.post('projects', data); return { id: extractResourceIDOfResponse(response) }; } async delete(id, isProjectName = false) { const headers = {}; if (isProjectName) { headers[HeaderName.IS_RESOURCE_NAME] = true; } await this.client.delete(`projects/${id}`, headers); } async update(id, data, isProjectName = false) { const headers = {}; if (isProjectName) { headers[HeaderName.IS_RESOURCE_NAME] = true; } await this.client.put(`projects/${id}`, data, headers); } async getMany(options) { options = options || {}; const response = await this.client.get(`projects${buildQueryString(options.query)}`); return { data: response.data, meta: extractResourceMetaOfResponse(response) }; } async getAll(options) { options = options || {}; options.query = options.query || {}; if (!options.query.page_size) { options.query.page_size = 50; } if (!options.query.page) { options.query.page = 1; } const response = await this.getMany(options); if (response.data.length === options.query.page_size) { options.query.page++; const next = await this.getAll(options); response.data.push(...next.data); } return response; } async getOne(id, isProjectName = false) { const headers = {}; if (isProjectName) { headers[HeaderName.IS_RESOURCE_NAME] = true; } const { data } = await this.client.get(`projects/${id}`, headers); return data; } // eslint-disable-next-line no-useless-constructor,@typescript-eslint/no-useless-constructor constructor(context){ super(context); } } /* * Copyright (c) 2022. * Author Peter Placzek (tada5hi) * For the full copyright and license information, * view the LICENSE file that was distributed with this source code. */ function parseLongProjectRepositoryName(name) { const index = name.indexOf('/'); if (index === -1) { throw new Error('The project repository name could not parsed.'); } const projectName = name.substring(0, index); let repositoryName = name.substring(projectName.length + 1); let artifactDigest; if (repositoryName.indexOf('@') !== -1) { const index = repositoryName.indexOf('@'); artifactDigest = repositoryName.substring(index + 1); repositoryName = repositoryName.substring(0, index); } let artifactTag; if (repositoryName.indexOf(':') !== -1) { const index = repositoryName.indexOf(':'); artifactTag = repositoryName.substring(index + 1); repositoryName = repositoryName.substring(0, index); } return { projectName, repositoryName, ...artifactDigest ? { artifactDigest } : {}, ...artifactTag ? { artifactTag } : {} }; } function buildProjectRepositoryLongName(representation) { const str = `${representation.projectName}/${representation.repositoryName}`; if (representation.artifactTag) { return `${str}:${representation.artifactTag}`; } if (representation.artifactDigest) { return `${str}@${representation.artifactDigest}`; } return str; } class ProjectRepositoryAPI extends BaseAPI { async findOne(input) { let context; if (typeof input === 'string') { context = parseLongProjectRepositoryName(input); } else { context = input; } const { data } = await this.getMany({ projectName: context.projectName, query: { q: { name: `~${context.repositoryName}` }, page_size: 1 } }); return data.shift(); } async getOne(input) { let context; if (typeof input === 'string') { context = parseLongProjectRepositoryName(input); } else { context = input; } const { data } = await this.client.get(`projects/${context.projectName}/repositories/${context.repositoryName}`); const parsed = parseLongProjectRepositoryName(data.name); return { ...data, name_short: parsed.repositoryName, project_name: parsed.projectName }; } async getMany(context) { const result = await this.client.get(`projects/${context.projectName}/repositories${buildQueryString(context.query)}`); return { data: result.data.map((item)=>{ const parsed = parseLongProjectRepositoryName(item.name); return { ...item, name_short: parsed.repositoryName, project_name: parsed.projectName }; }), meta: extractResourceMetaOfResponse(result) }; } async getAll(context) { context.query = context.query || {}; if (!context.query.page_size) { context.query.page_size = 50; } if (!context.query.page) { context.query.page = 1; } const response = await this.getMany(context); if (response.data.length === context.query.page_size) { context.query.page++; const next = await this.getAll(context); response.data.push(...next.data); } return response; } async update(context) { await this.client.put(`projects/${context.projectName}/repositories/${context.repositoryName}`, context.data); } async delete(input) { let context; if (typeof input === 'string') { context = parseLongProjectRepositoryName(input); } else { context = input; } await this.client.delete(`projects/${context.projectName}/repositories/${context.repositoryName}`); } // eslint-disable-next-line no-useless-constructor,@typescript-eslint/no-useless-constructor constructor(context){ super(context); } } class ProjectRepositoryArtifactAPI extends BaseAPI { async getMany(context) { const { data } = await this.client.get(`projects/${context.projectName}/repositories/${context.repositoryName}/artifacts${buildQueryString(context.query)}`); return data; } async copy(destination, source) { let from; if (typeof source === 'string') { from = source; } else { if (!source.artifactTag && !source.artifactDigest) { source.artifactTag = 'latest'; } from = buildProjectRepositoryLongName(source); } await this.client.post(`projects/${destination.projectName}/repositories/${destination.repositoryName}/artifacts?` + `from=${from}`); } async delete(context) { await this.client.delete(`projects/${context.projectName}/repositories/${context.repositoryName}/artifacts/${context.tagOrDigest || 'latest'}`); } // eslint-disable-next-line no-useless-constructor,@typescript-eslint/no-useless-constructor constructor(context){ super(context); } } class ProjectRepositoryArtifactLabelAPI extends BaseAPI { async create(options) { await this.client.post(`projects/${options.projectName}/repositories/${options.repositoryName}` + `/artifacts/${options.tagOrDigest || 'latest'}/labels`, { id: options.labelId }); } async delete(options) { await this.client.delete(`projects/${options.projectName}/repositories/${options.repositoryName}` + `/artifacts/${options.tagOrDigest || 'latest'}/labels/${options.labelId}`); } // eslint-disable-next-line no-useless-constructor,@typescript-eslint/no-useless-constructor constructor(context){ super(context); } } class ProjectWebhookPolicyAPI extends BaseAPI { async create(context) { const headers = {}; if (context.isProjectName) { headers[HeaderName.IS_RESOURCE_NAME] = true; } const response = await this.client.post(`projects/${context.projectIdOrName}/webhook/policies`, this.extendPayload(context.data), headers); return { id: extractResourceIDOfResponse(response) }; } async getMany(context) { const headers = {}; if (context.isProjectName) { headers[HeaderName.IS_RESOURCE_NAME] = true; } const response = await this.client.get(`projects/${context.projectIdOrName}/webhook/policies${buildQueryString(context.query)}`, headers); return { data: response.data, meta: extractResourceMetaOfResponse(response) }; } async getOne(context) { const headers = {}; if (context.isProjectName) { headers[HeaderName.IS_RESOURCE_NAME] = true; } const response = await this.client.get(`projects/${context.projectIdOrName}/webhook/policies/${context.id}`, headers); return response.data; } async findOne(context) { const response = await this.getMany({ projectIdOrName: context.projectIdOrName, isProjectName: context.isProjectName, query: { q: { name: context.name }, page_size: 1 } }); return response.data.pop(); } async update(context) { const headers = {}; if (context.isProjectName) { headers[HeaderName.IS_RESOURCE_NAME] = true; } await this.client.put(`projects/${context.projectIdOrName}/webhook/policies/${context.id}`, this.extendPayload({ ...context.data, id: context.id }), headers); } async deleteByName(context) { const webhook = await this.findOne(context); if (webhook) { await this.delete({ isProjectName: false, projectIdOrName: webhook.project_id, id: webhook.id }); } } async delete(context) { const headers = {}; if (context.isProjectName) { headers[HeaderName.IS_RESOURCE_NAME] = true; } await this.client.delete(`projects/${context.projectIdOrName}/webhook/policies/${context.id}`, headers); } extendPayload(data) { data.name = data.name || (Math.random() + 1).toString(36).substring(7); if (typeof data.enabled === 'undefined') { data.enabled = true; } if (typeof data.targets === 'undefined') { data.targets = []; } if (typeof data.event_types === 'undefined') { data.event_types = [ 'PUSH_ARTIFACT' ]; } else { data.event_types = smob.merge([ 'PUSH_ARTIFACT' ], data.event_types); } return data; } // eslint-disable-next-line no-useless-constructor,@typescript-eslint/no-useless-constructor constructor(context){ super(context); } } /* * Copyright (c) 2024. * Author Peter Placzek (tada5hi) * For the full copyright and license information, * view the LICENSE file that was distributed with this source code. */ var RobotPermissionResource = /*#__PURE__*/ function(RobotPermissionResource) { RobotPermissionResource["ARTIFACT"] = "artifact"; RobotPermissionResource["ARTIFACT_LABEL"] = "artifact-label"; RobotPermissionResource["IMMUTABLE_TAG"] = "immutable-tag"; RobotPermissionResource["LABEL"] = "label"; RobotPermissionResource["LOG"] = "log"; RobotPermissionResource["METADATA"] = "metadata"; RobotPermissionResource["NOTIFICATION_POLICY"] = "notification-policy"; RobotPermissionResource["PREHEAT_POLICY"] = "preheat-policy"; RobotPermissionResource["PROJECT"] = "project"; RobotPermissionResource["REPOSITORY"] = "repository"; RobotPermissionResource["SCAN"] = "scan"; RobotPermissionResource["TAG"] = "tag"; return RobotPermissionResource; }({}); var RobotPermissionAction = /*#__PURE__*/ function(RobotPermissionAction) { RobotPermissionAction["CREATE"] = "create"; RobotPermissionAction["DELETE"] = "delete"; RobotPermissionAction["READ"] = "read"; RobotPermissionAction["UPDATE"] = "update"; RobotPermissionAction["PULL"] = "pull"; RobotPermissionAction["PUSH"] = "push"; RobotPermissionAction["LIST"] = "list"; RobotPermissionAction["STOP"] = "stop"; return RobotPermissionAction; }({}); class RobotAPI extends BaseAPI { async create(data) { const response = await this.client.post('robots', this.extendPayload(data)); return smob.merge(response.data, data); } async getMany(context) { const response = await this.client.get(`robots${buildQueryString(context.query)}`); return { data: response.data, meta: extractResourceMetaOfResponse(response) }; } async getOne(id) { const response = await this.client.get(`robots/${id}`); return response.data; } /** * Update harbor project robot account. * If no "secret" provided, a new secret is generated. * * @param id * @param secret */ async updateSecret(id, secret) { const payload = { ...secret ? { secret } : {} }; const { data } = await this.client.patch(`robots/${id}`, payload); if (typeof payload.secret !== 'undefined') { data.secret = payload.secret; } return data; } async update(id, data) { await this.client.put(`robots/${id}`, this.extendPayload({ ...data, id })); } async delete(id) { await this.client.delete(`robots/${id}`); } extendPayload(data) { return smob.merge(data || {}, { description: '', duration: -1, level: 'system', editable: true, disable: false, permissions: [] }); } // eslint-disable-next-line no-useless-constructor,@typescript-eslint/no-useless-constructor constructor(context){ super(context); } } /** * Create robot permission to access all resources. * * @param namespace (e.g. * or project name) */ function buildRobotPermissionForAllResources(namespace) { return { access: [ { resource: RobotPermissionResource.ARTIFACT, action: RobotPermissionAction.CREATE }, { resource: RobotPermissionResource.ARTIFACT, action: RobotPermissionAction.DELETE }, { resource: RobotPermissionResource.ARTIFACT, action: RobotPermissionAction.LIST }, { resource: RobotPermissionResource.ARTIFACT, action: RobotPermissionAction.READ }, { resource: RobotPermissionResource.ARTIFACT_LABEL, action: RobotPermissionAction.CREATE }, { resource: RobotPermissionResource.ARTIFACT_LABEL, action: RobotPermissionAction.DELETE }, { resource: RobotPermissionResource.IMMUTABLE_TAG, action: RobotPermissionAction.CREATE }, { resource: RobotPermissionResource.IMMUTABLE_TAG, action: RobotPermissionAction.DELETE }, { resource: RobotPermissionResource.IMMUTABLE_TAG, action: RobotPermissionAction.LIST }, { resource: RobotPermissionResource.IMMUTABLE_TAG, action: RobotPermissionAction.UPDATE }, { resource: RobotPermissionResource.REPOSITORY, action: RobotPermissionAction.LIST }, { resource: RobotPermissionResource.REPOSITORY, action: RobotPermissionAction.PULL }, { resource: RobotPermissionResource.REPOSITORY, action: RobotPermissionAction.PUSH }, { resource: RobotPermissionResource.REPOSITORY, action: RobotPermissionAction.UPDATE }, { resource: RobotPermissionResource.REPOSITORY, action: RobotPermissionAction.DELETE }, { resource: RobotPermissionResource.TAG, action: RobotPermissionAction.CREATE }, { resource: RobotPermissionResource.TAG, action: RobotPermissionAction.DELETE }, { resource: RobotPermissionResource.TAG, action: RobotPermissionAction.LIST }, { resource: RobotPermissionResource.SCAN, action: RobotPermissionAction.READ }, { resource: RobotPermissionResource.SCAN, action: RobotPermissionAction.STOP }, { resource: RobotPermissionResource.SCAN, action: RobotPermissionAction.CREATE }, { resource: RobotPermissionResource.LABEL, action: RobotPermissionAction.CREATE }, { resource: RobotPermissionResource.LABEL, action: RobotPermissionAction.DELETE }, { resource: RobotPermissionResource.LABEL, action: RobotPermissionAction.LIST }, { resource: RobotPermissionResource.LABEL, action: RobotPermissionAction.READ }, { resource: RobotPermissionResource.LABEL, action: RobotPermissionAction.UPDATE }, { resource: RobotPermissionResource.METADATA, action: RobotPermissionAction.CREATE }, { resource: RobotPermissionResource.METADATA, action: RobotPermissionAction.DELETE }, { resource: RobotPermissionResource.METADATA, action: RobotPermissionAction.LIST }, { resource: RobotPermissionResource.METADATA, action: RobotPermissionAction.READ }, { resource: RobotPermissionResource.METADATA, action: RobotPermissionAction.UPDATE }, { resource: RobotPermissionResource.LOG, action: RobotPermissionAction.LIST }, { resource: RobotPermissionResource.NOTIFICATION_POLICY, action: RobotPermissionAction.CREATE }, { resource: RobotPermissionResource.NOTIFICATION_POLICY, action: RobotPermissionAction.DELETE }, { resource: RobotPermissionResource.NOTIFICATION_POLICY, action: RobotPermissionAction.LIST }, { resource: RobotPermissionResource.NOTIFICATION_POLICY, action: RobotPermissionAction.READ }, { resource: RobotPermissionResource.NOTIFICATION_POLICY, action: RobotPermissionAction.UPDATE }, { resource: RobotPermissionResource.PREHEAT_POLICY, action: RobotPermissionAction.CREATE }, { resource: RobotPermissionResource.PREHEAT_POLICY, action: RobotPermissionAction.DELETE }, { resource: RobotPermissionResource.PREHEAT_POLICY, action: RobotPermissionAction.LIST }, { resource: RobotPermissionResource.PREHEAT_POLICY, action: RobotPermissionAction.READ }, { resource: RobotPermissionResource.PREHEAT_POLICY, action: RobotPermissionAction.UPDATE }, { resource: RobotPermissionResource.PROJECT, action: RobotPermissionAction.DELETE }, { resource: RobotPermissionResource.PROJECT, action: RobotPermissionAction.READ }, { resource: RobotPermissionResource.PROJECT, action: RobotPermissionAction.UPDATE } ], kind: 'project', namespace }; } class HarborClient extends hapic.Client { // ----------------------------------------------------------------------------------- applyConfig(input) { input = input || {}; let connectionOptions; if (input.connectionString) { connectionOptions = parseConnectionString(input.connectionString); } if (input.connectionOptions) { connectionOptions = input.connectionOptions; } if (connectionOptions) { this.setBaseURL(connectionOptions.host); this.setAuthorizationHeader({ type: 'Basic', username: connectionOptions.user, password: connectionOptions.password }); } } // ----------------------------------------------------------------------------------- async search(q) { const { data } = await this.get(`search?q=${q}`); return data; } // ----------------------------------------------------------------------------------- constructor(input){ input = input || {}; super(input.request); this.project = new ProjectAPI({ client: this }); this.projectRepository = new ProjectRepositoryAPI({ client: this }); this.projectRepositoryArtifact = new ProjectRepositoryArtifactAPI({ client: this }); this.projectRepositoryArtifactLabel = new ProjectRepositoryArtifactLabelAPI({ client: this }); this.projectWebhookPolicy = new ProjectWebhookPolicyAPI({ client: this }); this.robot = new RobotAPI({ client: this }); this.applyConfig(input); } } const instances = {}; /** * Verify if a harbor client singleton instance exists. * * @param key */ function hasClient(key) { return hapic.hasOwnProperty(instances, key || 'default'); } /** * Set the harbor client singleton instance. * * @param client * @param key */ function setClient(client, key) { key = key || 'default'; instances[key] = client; return client; } /** * Receive a harbor singleton instance. * * @param key */ function useClient(key) { key = key || 'default'; if (Object.prototype.hasOwnProperty.call(instances, key)) { return instances[key]; } const instance = createClient(); instances[key] = instance; return instance; } /** * Unset a harbor client singleton instance. * * @param key */ function unsetClient(key) { key = key || 'default'; if (hapic.hasOwnProperty(instances, key)) { delete instances[key]; } } /** * Create a harbor client. * * @param input */ function createClient(input) { return new HarborClient(input); } /** * Check if the argument is of instance Client. * * @param input */ function isClient(input) { if (input instanceof HarborClient) { return true; } return hapic.verifyInstanceBySymbol(input, 'HarborClient'); } const client = createClient(); Object.defineProperty(exports, "isClientError", { enumerable: true, get: function () { return hapic.isClientError; } }); Object.defineProperty(exports, "isClientErrorDueNetworkIssue", { enumerable: true, get: function () { return hapic.isClientErrorDueNetworkIssue; } }); Object.defineProperty(exports, "isClientErrorWithStatusCode", { enumerable: true, get: function () { return hapic.isClientErrorWithStatusCode; } }); exports.HarborClient = HarborClient; exports.HeaderName = HeaderName; exports.ProjectAPI = ProjectAPI; exports.ProjectRepositoryAPI = ProjectRepositoryAPI; exports.ProjectRepositoryArtifactAPI = ProjectRepositoryArtifactAPI; exports.ProjectRepositoryArtifactLabelAPI = ProjectRepositoryArtifactLabelAPI; exports.ProjectWebhookPolicyAPI = ProjectWebhookPolicyAPI; exports.RobotAPI = RobotAPI; exports.RobotPermissionAction = RobotPermissionAction; exports.RobotPermissionResource = RobotPermissionResource; exports.buildProjectRepositoryLongName = buildProjectRepositoryLongName; exports.buildQueryString = buildQueryString; exports.buildRobotPermissionForAllResources = buildRobotPermissionForAllResources; exports.createClient = createClient; exports.default = client; exports.extractResourceIDOfResponse = extractResourceIDOfResponse; exports.extractResourceMetaOfResponse = extractResourceMetaOfResponse; exports.hasClient = hasClient; exports.isClient = isClient; exports.parseConnectionString = parseConnectionString; exports.parseLongProjectRepositoryName = parseLongProjectRepositoryName; exports.setClient = setClient; exports.unsetClient = unsetClient; exports.useClient = useClient; module.exports = Object.assign(exports.default, exports); //# sourceMappingURL=index.cjs.map