mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2025-04-26 15:09:53 +03:00
feat: add option REGISTRY_SECURED
for registries with Basic Auth
This commit is contained in:
parent
684f82f24e
commit
ffb6d14baf
12 changed files with 35 additions and 8 deletions
|
@ -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_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
|
- `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
|
- `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/).
|
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/).
|
||||||
|
|
||||||
|
|
|
@ -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_MIN_BRANCHES}~${CATALOG_MIN_BRANCHES}~" index.html
|
||||||
sed -i "s~\${CATALOG_MAX_BRANCHES}~${CATALOG_MAX_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~\${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
|
grep -o 'THEME[A-Z_]*' index.html | while read e; do
|
||||||
sed -i "s~\${$e}~$(printenv $e)~" index.html
|
sed -i "s~\${$e}~$(printenv $e)~" index.html
|
||||||
|
|
|
@ -50,6 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
on-notify="{ props.onnNotify }"
|
on-notify="{ props.onnNotify }"
|
||||||
on-authentication="{ props.onAuthentication }"
|
on-authentication="{ props.onAuthentication }"
|
||||||
show-catalog-nb-tags="{ props.showCatalogNbTags }"
|
show-catalog-nb-tags="{ props.showCatalogNbTags }"
|
||||||
|
is-registry-secured="{ props.isRegistrySecured }"
|
||||||
class="animated {!state.expanded && !props.filterResults ? 'hide' : ''} {state.expanding ? 'expanding' : ''}"
|
class="animated {!state.expanded && !props.filterResults ? 'hide' : ''} {state.expanding ? 'expanding' : ''}"
|
||||||
each="{item in state.images}"
|
each="{item in state.images}"
|
||||||
z-index="{ props.zIndex - 1 }"
|
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 self = this;
|
||||||
const oReq = new Http({
|
const oReq = new Http({
|
||||||
onAuthentication: props.onAuthentication,
|
onAuthentication: props.onAuthentication,
|
||||||
|
withCredentials: props.isRegistrySecured,
|
||||||
});
|
});
|
||||||
oReq.addEventListener('load', function () {
|
oReq.addEventListener('load', function () {
|
||||||
if (this.status === 200) {
|
if (this.status === 200) {
|
||||||
|
|
|
@ -36,6 +36,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
show-catalog-nb-tags="{ props.showCatalogNbTags }"
|
show-catalog-nb-tags="{ props.showCatalogNbTags }"
|
||||||
catalog-default-expanded="{ props.catalogDefaultExpanded || state.nRepositories === 1 }"
|
catalog-default-expanded="{ props.catalogDefaultExpanded || state.nRepositories === 1 }"
|
||||||
z-index="{ props.catalogMaxBranches - props.catalogMinBranches + 2 }"
|
z-index="{ props.catalogMaxBranches - props.catalogMinBranches + 2 }"
|
||||||
|
is-registry-secured="{ props.isRegistrySecured }"
|
||||||
></catalog-element>
|
></catalog-element>
|
||||||
<script>
|
<script>
|
||||||
import CatalogElement from './catalog-element.riot';
|
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 catalogUrl = `${props.registryUrl}/v2/_catalog?n=${state.catalogElementsLimit}`;
|
||||||
const oReq = new Http({
|
const oReq = new Http({
|
||||||
onAuthentication: this.props.onAuthentication,
|
onAuthentication: this.props.onAuthentication,
|
||||||
|
withCredentials: props.isRegistrySecured,
|
||||||
});
|
});
|
||||||
oReq.addEventListener('load', function () {
|
oReq.addEventListener('load', function () {
|
||||||
if (this.status === 200) {
|
if (this.status === 200) {
|
||||||
|
|
|
@ -58,10 +58,11 @@
|
||||||
},
|
},
|
||||||
deleteImages() {
|
deleteImages() {
|
||||||
this.props.toDelete.forEach((image) => this.getContentDigestThenDelete(image, this.props));
|
this.props.toDelete.forEach((image) => this.getContentDigestThenDelete(image, this.props));
|
||||||
|
this.props.onImageDeleted();
|
||||||
},
|
},
|
||||||
getContentDigestThenDelete({ name, tag }, opts) {
|
getContentDigestThenDelete({ name, tag }, opts) {
|
||||||
const { registryUrl, onNotify, onAuthentication } = opts;
|
const { registryUrl, onNotify, onAuthentication, isRegistrySecured } = opts;
|
||||||
const oReq = new Http({ onAuthentication });
|
const oReq = new Http({ onAuthentication, withCredentials: isRegistrySecured });
|
||||||
const self = this;
|
const self = this;
|
||||||
oReq.addEventListener('loadend', function () {
|
oReq.addEventListener('loadend', function () {
|
||||||
if (this.status === 200 || this.status === 202) {
|
if (this.status === 200 || this.status === 202) {
|
||||||
|
@ -86,8 +87,8 @@
|
||||||
oReq.send();
|
oReq.send();
|
||||||
},
|
},
|
||||||
deleteImage({ name, tag, contentDigest }, opts) {
|
deleteImage({ name, tag, contentDigest }, opts) {
|
||||||
const { registryUrl, ignoreError, onNotify, onAuthentication, onClick } = opts;
|
const { registryUrl, ignoreError, onNotify, onAuthentication, onClick, isRegistrySecured } = opts;
|
||||||
const oReq = new Http({ onAuthentication });
|
const oReq = new Http({ onAuthentication, withCredentials: isRegistrySecured });
|
||||||
oReq.addEventListener('loadend', function () {
|
oReq.addEventListener('loadend', function () {
|
||||||
if (this.status === 200 || this.status === 202) {
|
if (this.status === 200 || this.status === 202) {
|
||||||
router.taglist(name);
|
router.taglist(name);
|
||||||
|
|
|
@ -59,6 +59,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
catalog-default-expanded="{ truthy(props.catalogDefaultExpanded) }"
|
catalog-default-expanded="{ truthy(props.catalogDefaultExpanded) }"
|
||||||
catalog-min-branches="{ props.catalogMinBranches }"
|
catalog-min-branches="{ props.catalogMinBranches }"
|
||||||
catalog-max-branches="{ props.catalogMaxBranches }"
|
catalog-max-branches="{ props.catalogMaxBranches }"
|
||||||
|
is-registry-secured="{ truthy(props.isRegistrySecured) }"
|
||||||
></catalog>
|
></catalog>
|
||||||
</route>
|
</route>
|
||||||
<route path="{baseRoute}taglist/(.*)">
|
<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) }"
|
use-control-cache-header="{ truthy(props.useControlCacheHeader) }"
|
||||||
taglist-order="{ props.taglistOrder }"
|
taglist-order="{ props.taglistOrder }"
|
||||||
tags-per-page="{ props.tagsPerPage }"
|
tags-per-page="{ props.tagsPerPage }"
|
||||||
|
is-registry-secured="{ truthy(props.isRegistrySecured) }"
|
||||||
></tag-list>
|
></tag-list>
|
||||||
</route>
|
</route>
|
||||||
<route path="{baseRoute}taghistory/(.*)">
|
<route path="{baseRoute}taghistory/(.*)">
|
||||||
|
@ -89,6 +91,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
on-authentication="{ onAuthentication }"
|
on-authentication="{ onAuthentication }"
|
||||||
history-custom-labels="{ stringToArray(props.historyCustomLabels) }"
|
history-custom-labels="{ stringToArray(props.historyCustomLabels) }"
|
||||||
use-control-cache-header="{ truthy(props.useControlCacheHeader) }"
|
use-control-cache-header="{ truthy(props.useControlCacheHeader) }"
|
||||||
|
is-registry-secured="{ truthy(props.isRegistrySecured) }"
|
||||||
></tag-history>
|
></tag-history>
|
||||||
</route>
|
</route>
|
||||||
</router>
|
</router>
|
||||||
|
|
|
@ -89,6 +89,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
onNotify: props.onNotify,
|
onNotify: props.onNotify,
|
||||||
onAuthentication: props.onAuthentication,
|
onAuthentication: props.onAuthentication,
|
||||||
useControlCacheHeader: props.useControlCacheHeader,
|
useControlCacheHeader: props.useControlCacheHeader,
|
||||||
|
isRegistrySecured: props.isRegistrySecured,
|
||||||
});
|
});
|
||||||
state.image.fillInfo();
|
state.image.fillInfo();
|
||||||
},
|
},
|
||||||
|
|
|
@ -58,6 +58,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
filter-results="{ props.filterResults }"
|
filter-results="{ props.filterResults }"
|
||||||
on-authentication="{ props.onAuthentication }"
|
on-authentication="{ props.onAuthentication }"
|
||||||
tags-per-page="{ props.tagsPerPage }"
|
tags-per-page="{ props.tagsPerPage }"
|
||||||
|
is-registry-secured="{ props.isRegistrySecured }"
|
||||||
|
on-image-deleted="{ () => state.reload() }"
|
||||||
>
|
>
|
||||||
</tag-table>
|
</tag-table>
|
||||||
|
|
||||||
|
@ -103,10 +105,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
this.tagComparator = getTagComparator(props.taglistOrder);
|
this.tagComparator = getTagComparator(props.taglistOrder);
|
||||||
},
|
},
|
||||||
display(props, state) {
|
display(props, state) {
|
||||||
|
state.reload = () => setTimeout(() => this.display(props, state), 1000);
|
||||||
state.tags = [];
|
state.tags = [];
|
||||||
const self = this;
|
const self = this;
|
||||||
const oReq = new Http({
|
const oReq = new Http({
|
||||||
onAuthentication: props.onAuthentication,
|
onAuthentication: props.onAuthentication,
|
||||||
|
withCredentials: props.isRegistrySecured,
|
||||||
});
|
});
|
||||||
oReq.addEventListener('load', function () {
|
oReq.addEventListener('load', function () {
|
||||||
if (this.status === 200) {
|
if (this.status === 200) {
|
||||||
|
@ -119,6 +123,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
onNotify: props.onNotify,
|
onNotify: props.onNotify,
|
||||||
onAuthentication: props.onAuthentication,
|
onAuthentication: props.onAuthentication,
|
||||||
useControlCacheHeader: props.useControlCacheHeader,
|
useControlCacheHeader: props.useControlCacheHeader,
|
||||||
|
isRegistrySecured: props.isRegistrySecured,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.sort(self.tagComparator);
|
.sort(self.tagComparator);
|
||||||
|
|
|
@ -23,6 +23,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
on-authentication="{ props.onAuthentication }"
|
on-authentication="{ props.onAuthentication }"
|
||||||
tags="{ props.tags }"
|
tags="{ props.tags }"
|
||||||
to-delete="{ state.toDelete }"
|
to-delete="{ state.toDelete }"
|
||||||
|
is-registry-secured="{ props.isRegistrySecured }"
|
||||||
|
on-image-deleted="{ props.onImageDeleted }"
|
||||||
></confirm-delete-image>
|
></confirm-delete-image>
|
||||||
<material-card class="taglist">
|
<material-card class="taglist">
|
||||||
<table style="border: none">
|
<table style="border: none">
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
catalog-default-expanded="${CATALOG_DEFAULT_EXPANDED}"
|
catalog-default-expanded="${CATALOG_DEFAULT_EXPANDED}"
|
||||||
catalog-min-branches="${CATALOG_MIN_BRANCHES}"
|
catalog-min-branches="${CATALOG_MIN_BRANCHES}"
|
||||||
catalog-max-branches="${CATALOG_MAX_BRANCHES}"
|
catalog-max-branches="${CATALOG_MAX_BRANCHES}"
|
||||||
|
is-registry-secured="${REGISTRY_SECURED}"
|
||||||
theme="${THEME}"
|
theme="${THEME}"
|
||||||
theme-primary-text="${THEME_PRIMARY_TEXT}"
|
theme-primary-text="${THEME_PRIMARY_TEXT}"
|
||||||
theme-neutral-text="${THEME_NEUTRAL_TEXT}"
|
theme-neutral-text="${THEME_NEUTRAL_TEXT}"
|
||||||
|
@ -82,6 +83,7 @@
|
||||||
catalog-default-expanded=""
|
catalog-default-expanded=""
|
||||||
catalog-min-branches="1"
|
catalog-min-branches="1"
|
||||||
catalog-max-branches="1"
|
catalog-max-branches="1"
|
||||||
|
is-registry-secured="false"
|
||||||
theme="auto"
|
theme="auto"
|
||||||
theme-primary-text=""
|
theme-primary-text=""
|
||||||
theme-neutral-text=""
|
theme-neutral-text=""
|
||||||
|
|
|
@ -42,7 +42,7 @@ export const platformToString = (platform) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export class DockerImage {
|
export class DockerImage {
|
||||||
constructor(name, tag, { list, registryUrl, onNotify, onAuthentication, useControlCacheHeader }) {
|
constructor(name, tag, { list, registryUrl, onNotify, onAuthentication, useControlCacheHeader, isRegistrySecured }) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
this.chars = 0;
|
this.chars = 0;
|
||||||
|
@ -52,6 +52,7 @@ export class DockerImage {
|
||||||
onNotify,
|
onNotify,
|
||||||
onAuthentication,
|
onAuthentication,
|
||||||
useControlCacheHeader,
|
useControlCacheHeader,
|
||||||
|
isRegistrySecured,
|
||||||
};
|
};
|
||||||
this.ociImage = false;
|
this.ociImage = false;
|
||||||
observable(this);
|
observable(this);
|
||||||
|
@ -91,7 +92,10 @@ export class DockerImage {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._fillInfoWaiting = true;
|
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;
|
const self = this;
|
||||||
oReq.addEventListener('loadend', function () {
|
oReq.addEventListener('loadend', function () {
|
||||||
if (this.status === 200 || this.status === 202) {
|
if (this.status === 200 || this.status === 202) {
|
||||||
|
@ -148,7 +152,10 @@ export class DockerImage {
|
||||||
oReq.send();
|
oReq.send();
|
||||||
}
|
}
|
||||||
getBlobs(blob) {
|
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;
|
const self = this;
|
||||||
oReq.addEventListener('loadend', function () {
|
oReq.addEventListener('loadend', function () {
|
||||||
if (this.status === 200 || this.status === 202) {
|
if (this.status === 200 || this.status === 202) {
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* 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 {
|
export class Http {
|
||||||
constructor(opts) {
|
constructor(opts) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue