feat: add option `REGISTRY_SECURED` for registries with Basic Auth

This commit is contained in:
Joxit 2023-06-06 05:56:37 +02:00
parent 684f82f24e
commit ffb6d14baf
No known key found for this signature in database
GPG Key ID: F526592B8E012263
12 changed files with 35 additions and 8 deletions

View File

@ -103,6 +103,7 @@ Some env options are available for use this interface for **only one server** (w
- `CATALOG_MIN_BRANCHES`: Set the minimum repository/namespace to expand (e.g. `joxit/docker-registry-ui` `joxit/` is the repository/namespace). Can be 0 to disable branching. (see [#319](https://github.com/Joxit/docker-registry-ui/pull/319)). (default: `1`). Since 2.5.0
- `CATALOG_MAX_BRANCHES`: Set the maximum repository/namespace to expand (e.g. `joxit/docker-registry-ui` `joxit/` is the repository/namespace). Can be 0 to disable branching. (see [#319](https://github.com/Joxit/docker-registry-ui/pull/319)). (default: `1`). Since 2.5.0
- `TAGLIST_PAGE_SIZE`: Set the number of tags to display in one page. (default: `100`). Since 2.5.0
- `REGISTRY_SECURED`: By default, the UI will check on every requests if your registry is secured or not (you will see `401` responses in your console). Set to `true` if your registry uses Basic Authentication and divide by two the number of call to your registry. (default `false`). Since 2.5.0
There are some examples with [docker-compose](https://docs.docker.com/compose/) and docker-registry-ui as proxy [here](https://github.com/Joxit/docker-registry-ui/tree/main/examples/ui-as-proxy/) or docker-registry-ui as standalone [here](https://github.com/Joxit/docker-registry-ui/tree/main/examples/ui-as-standalone/).

View File

@ -16,6 +16,7 @@ sed -i "s~\${CATALOG_DEFAULT_EXPANDED}~${CATALOG_DEFAULT_EXPANDED}~" index.html
sed -i "s~\${CATALOG_MIN_BRANCHES}~${CATALOG_MIN_BRANCHES}~" index.html
sed -i "s~\${CATALOG_MAX_BRANCHES}~${CATALOG_MAX_BRANCHES}~" index.html
sed -i "s~\${TAGLIST_PAGE_SIZE}~${TAGLIST_PAGE_SIZE}~" index.html
sed -i "s~\${REGISTRY_SECURED}~${REGISTRY_SECURED}~" index.html
grep -o 'THEME[A-Z_]*' index.html | while read e; do
sed -i "s~\${$e}~$(printenv $e)~" index.html

View File

@ -50,6 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
on-notify="{ props.onnNotify }"
on-authentication="{ props.onAuthentication }"
show-catalog-nb-tags="{ props.showCatalogNbTags }"
is-registry-secured="{ props.isRegistrySecured }"
class="animated {!state.expanded && !props.filterResults ? 'hide' : ''} {state.expanding ? 'expanding' : ''}"
each="{item in state.images}"
z-index="{ props.zIndex - 1 }"
@ -108,6 +109,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const self = this;
const oReq = new Http({
onAuthentication: props.onAuthentication,
withCredentials: props.isRegistrySecured,
});
oReq.addEventListener('load', function () {
if (this.status === 200) {

View File

@ -36,6 +36,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
show-catalog-nb-tags="{ props.showCatalogNbTags }"
catalog-default-expanded="{ props.catalogDefaultExpanded || state.nRepositories === 1 }"
z-index="{ props.catalogMaxBranches - props.catalogMinBranches + 2 }"
is-registry-secured="{ props.isRegistrySecured }"
></catalog-element>
<script>
import CatalogElement from './catalog-element.riot';
@ -81,6 +82,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const catalogUrl = `${props.registryUrl}/v2/_catalog?n=${state.catalogElementsLimit}`;
const oReq = new Http({
onAuthentication: this.props.onAuthentication,
withCredentials: props.isRegistrySecured,
});
oReq.addEventListener('load', function () {
if (this.status === 200) {

View File

@ -58,10 +58,11 @@
},
deleteImages() {
this.props.toDelete.forEach((image) => this.getContentDigestThenDelete(image, this.props));
this.props.onImageDeleted();
},
getContentDigestThenDelete({ name, tag }, opts) {
const { registryUrl, onNotify, onAuthentication } = opts;
const oReq = new Http({ onAuthentication });
const { registryUrl, onNotify, onAuthentication, isRegistrySecured } = opts;
const oReq = new Http({ onAuthentication, withCredentials: isRegistrySecured });
const self = this;
oReq.addEventListener('loadend', function () {
if (this.status === 200 || this.status === 202) {
@ -86,8 +87,8 @@
oReq.send();
},
deleteImage({ name, tag, contentDigest }, opts) {
const { registryUrl, ignoreError, onNotify, onAuthentication, onClick } = opts;
const oReq = new Http({ onAuthentication });
const { registryUrl, ignoreError, onNotify, onAuthentication, onClick, isRegistrySecured } = opts;
const oReq = new Http({ onAuthentication, withCredentials: isRegistrySecured });
oReq.addEventListener('loadend', function () {
if (this.status === 200 || this.status === 202) {
router.taglist(name);

View File

@ -59,6 +59,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
catalog-default-expanded="{ truthy(props.catalogDefaultExpanded) }"
catalog-min-branches="{ props.catalogMinBranches }"
catalog-max-branches="{ props.catalogMaxBranches }"
is-registry-secured="{ truthy(props.isRegistrySecured) }"
></catalog>
</route>
<route path="{baseRoute}taglist/(.*)">
@ -75,6 +76,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
use-control-cache-header="{ truthy(props.useControlCacheHeader) }"
taglist-order="{ props.taglistOrder }"
tags-per-page="{ props.tagsPerPage }"
is-registry-secured="{ truthy(props.isRegistrySecured) }"
></tag-list>
</route>
<route path="{baseRoute}taghistory/(.*)">
@ -89,6 +91,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
on-authentication="{ onAuthentication }"
history-custom-labels="{ stringToArray(props.historyCustomLabels) }"
use-control-cache-header="{ truthy(props.useControlCacheHeader) }"
is-registry-secured="{ truthy(props.isRegistrySecured) }"
></tag-history>
</route>
</router>

View File

@ -89,6 +89,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
onNotify: props.onNotify,
onAuthentication: props.onAuthentication,
useControlCacheHeader: props.useControlCacheHeader,
isRegistrySecured: props.isRegistrySecured,
});
state.image.fillInfo();
},

View File

@ -58,6 +58,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
filter-results="{ props.filterResults }"
on-authentication="{ props.onAuthentication }"
tags-per-page="{ props.tagsPerPage }"
is-registry-secured="{ props.isRegistrySecured }"
on-image-deleted="{ () => state.reload() }"
>
</tag-table>
@ -103,10 +105,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
this.tagComparator = getTagComparator(props.taglistOrder);
},
display(props, state) {
state.reload = () => setTimeout(() => this.display(props, state), 1000);
state.tags = [];
const self = this;
const oReq = new Http({
onAuthentication: props.onAuthentication,
withCredentials: props.isRegistrySecured,
});
oReq.addEventListener('load', function () {
if (this.status === 200) {
@ -119,6 +123,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
onNotify: props.onNotify,
onAuthentication: props.onAuthentication,
useControlCacheHeader: props.useControlCacheHeader,
isRegistrySecured: props.isRegistrySecured,
})
)
.sort(self.tagComparator);

View File

@ -23,6 +23,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
on-authentication="{ props.onAuthentication }"
tags="{ props.tags }"
to-delete="{ state.toDelete }"
is-registry-secured="{ props.isRegistrySecured }"
on-image-deleted="{ props.onImageDeleted }"
></confirm-delete-image>
<material-card class="taglist">
<table style="border: none">

View File

@ -51,6 +51,7 @@
catalog-default-expanded="${CATALOG_DEFAULT_EXPANDED}"
catalog-min-branches="${CATALOG_MIN_BRANCHES}"
catalog-max-branches="${CATALOG_MAX_BRANCHES}"
is-registry-secured="${REGISTRY_SECURED}"
theme="${THEME}"
theme-primary-text="${THEME_PRIMARY_TEXT}"
theme-neutral-text="${THEME_NEUTRAL_TEXT}"
@ -82,6 +83,7 @@
catalog-default-expanded=""
catalog-min-branches="1"
catalog-max-branches="1"
is-registry-secured="false"
theme="auto"
theme-primary-text=""
theme-neutral-text=""

View File

@ -42,7 +42,7 @@ export const platformToString = (platform) => {
};
export class DockerImage {
constructor(name, tag, { list, registryUrl, onNotify, onAuthentication, useControlCacheHeader }) {
constructor(name, tag, { list, registryUrl, onNotify, onAuthentication, useControlCacheHeader, isRegistrySecured }) {
this.name = name;
this.tag = tag;
this.chars = 0;
@ -52,6 +52,7 @@ export class DockerImage {
onNotify,
onAuthentication,
useControlCacheHeader,
isRegistrySecured,
};
this.ociImage = false;
observable(this);
@ -91,7 +92,10 @@ export class DockerImage {
return;
}
this._fillInfoWaiting = true;
const oReq = new Http({ onAuthentication: this.opts.onAuthentication });
const oReq = new Http({
onAuthentication: this.opts.onAuthentication,
withCredentials: this.opts.isRegistrySecured,
});
const self = this;
oReq.addEventListener('loadend', function () {
if (this.status === 200 || this.status === 202) {
@ -148,7 +152,10 @@ export class DockerImage {
oReq.send();
}
getBlobs(blob) {
const oReq = new Http({ onAuthentication: this.opts.onAuthentication });
const oReq = new Http({
onAuthentication: this.opts.onAuthentication,
withCredentials: this.opts.isRegistrySecured,
});
const self = this;
oReq.addEventListener('loadend', function () {
if (this.status === 200 || this.status === 202) {

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { getFromCache, setCache } from './cache-request';
import { getFromCache, setCache } from './cache-request.js';
export class Http {
constructor(opts) {