Files
caprover/src/datastore/RegistriesDataStore.ts
T
Kasra Bigdeli 4a32cb9dc3 Updated packages (#2165)
* Updated packages

* Updated packages

* Fixed formatting

* Fixed tests
2024-10-17 21:16:25 -07:00

285 lines
9.2 KiB
TypeScript

import { v4 as uuid } from 'uuid'
import ApiStatusCodes from '../api/ApiStatusCodes'
import {
IRegistryInfo,
IRegistryInfoEncrypted,
IRegistryType,
IRegistryTypes,
} from '../models/IRegistryInfo'
import CaptainEncryptor from '../utils/Encryptor'
import configstore = require('configstore')
const DOCKER_REGISTRIES = 'dockerRegistries'
const DEFAULT_DOCKER_REGISTRY_ID = 'defaultDockerRegId'
class RegistriesDataStore {
private encryptor: CaptainEncryptor
constructor(
private data: configstore,
public namepace: string
) {}
setEncryptor(encryptor: CaptainEncryptor) {
this.encryptor = encryptor
}
getDefaultPushRegistryId(): Promise<string | undefined> {
const self = this
return Promise.resolve().then(function () {
return self.data.get(DEFAULT_DOCKER_REGISTRY_ID)
})
}
setDefaultPushRegistryId(registryId: string) {
const self = this
return Promise.resolve()
.then(function () {
return self.getAllRegistries()
})
.then(function (registries) {
let found = false
for (let i = 0; i < registries.length; i++) {
const registry = registries[i]
if (registry.id === registryId) {
found = true
}
}
// registryId can be NULL/Empty, meaning that no registry will be the default push registry
if (!found && !!registryId) {
throw ApiStatusCodes.createError(
ApiStatusCodes.NOT_FOUND,
'Registry not found'
)
}
self.data.set(DEFAULT_DOCKER_REGISTRY_ID, registryId)
})
}
getRegistryById(registryId: string) {
const self = this
return Promise.resolve()
.then(function () {
if (!registryId) throw new Error('Empty registry id!')
return self.getAllRegistries()
})
.then(function (registries) {
for (let i = 0; i < registries.length; i++) {
const registry = registries[i]
if (registry.id === registryId) {
return registry
}
}
throw ApiStatusCodes.createError(
ApiStatusCodes.NOT_FOUND,
'Registry not found'
)
})
}
deleteRegistry(registryId: string) {
const self = this
return Promise.resolve()
.then(function () {
if (!registryId) throw new Error('Empty registry id to delete!')
return self.getAllRegistries()
})
.then(function (registries) {
const newReg = []
for (let i = 0; i < registries.length; i++) {
const registry = registries[i]
if (registry.id !== registryId) {
newReg.push(registry)
}
}
if (newReg.length === registries.length) {
throw ApiStatusCodes.createError(
ApiStatusCodes.NOT_FOUND,
'Registry not found'
)
}
self.saveAllRegistries(newReg)
})
}
getAllRegistries() {
const self = this
return Promise.resolve()
.then(function () {
return self.data.get(DOCKER_REGISTRIES) || []
})
.then(function (registries: IRegistryInfoEncrypted[]) {
const unencryptedList: IRegistryInfo[] = []
for (let i = 0; i < registries.length; i++) {
const element = registries[i]
unencryptedList.push({
id: element.id,
registryDomain: element.registryDomain,
registryImagePrefix: element.registryImagePrefix,
registryUser: element.registryUser,
registryPassword: self.encryptor.decrypt(
element.registryPasswordEncrypted
),
registryType: element.registryType,
})
}
return unencryptedList
})
}
updateRegistry(
id: string,
registryUser: string,
registryPassword: string,
registryDomain: string,
registryImagePrefix: string
) {
const self = this
return Promise.resolve()
.then(function () {
if (
!id ||
!registryUser ||
!registryPassword ||
!registryDomain
) {
throw ApiStatusCodes.createError(
ApiStatusCodes.ILLEGAL_PARAMETER,
'User, password and domain are required.'
)
}
return self.getAllRegistries()
})
.then(function (registries) {
let found = false
for (let idx = 0; idx < registries.length; idx++) {
const element = registries[idx]
if (element.id === id) {
if (element.registryType === IRegistryTypes.LOCAL_REG) {
throw ApiStatusCodes.createError(
ApiStatusCodes.ILLEGAL_OPERATION,
'You cannot edit self-hosted registry'
)
}
element.registryUser = registryUser
element.registryPassword = registryPassword
element.registryDomain = registryDomain
element.registryImagePrefix = registryImagePrefix
found = true
}
}
if (!found)
throw ApiStatusCodes.createError(
ApiStatusCodes.NOT_FOUND,
'Registry ID not found'
)
return self.saveAllRegistries(registries)
})
}
addRegistryToDb(
registryUser: string,
registryPassword: string,
registryDomain: string,
registryImagePrefix: string,
registryType: IRegistryType
) {
const self = this
let savedId: string | undefined = undefined
return Promise.resolve()
.then(function () {
if (
!registryUser ||
!registryPassword ||
!registryDomain ||
!registryType
) {
throw ApiStatusCodes.createError(
ApiStatusCodes.ILLEGAL_PARAMETER,
'User, password and domain are required.'
)
}
return self.getAllRegistries()
})
.then(function (registries) {
let id: string = uuid()
let isAlreadyTaken = true
while (isAlreadyTaken) {
id = uuid()
isAlreadyTaken = false
for (let i = 0; i < registries.length; i++) {
if (registries[i].id === id) {
isAlreadyTaken = true
break
}
}
}
savedId = id
registries.push({
id,
registryUser,
registryPassword,
registryDomain,
registryImagePrefix,
registryType,
})
return self.saveAllRegistries(registries)
})
.then(function () {
if (!savedId)
throw new Error(
'Saved registry, but ID is null. This should never happen'
)
return savedId
})
}
private saveAllRegistries(registries: IRegistryInfo[]) {
const self = this
return Promise.resolve() //
.then(function () {
const encryptedList: IRegistryInfoEncrypted[] = []
for (let i = 0; i < registries.length; i++) {
const element = registries[i]
encryptedList.push({
id: element.id,
registryDomain: element.registryDomain,
registryImagePrefix: element.registryImagePrefix,
registryUser: element.registryUser,
registryPasswordEncrypted: self.encryptor.encrypt(
element.registryPassword
),
registryType: element.registryType,
})
}
self.data.set(DOCKER_REGISTRIES, encryptedList)
})
}
}
export default RegistriesDataStore