Skip to content

Commit

Permalink
Add basic redirect support
Browse files Browse the repository at this point in the history
Related to #559

Signed-off-by: stianst <[email protected]>
Signed-off-by: Alexander Schwartz <[email protected]>
Co-authored-by: Alexander Schwartz <[email protected]>
  • Loading branch information
stianst and ahus1 authored Feb 3, 2025
1 parent 878ec65 commit 8705691
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 34 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ There's also an auto-builder utility that watches the filesystem and continuousl

To serve the website locally with a web browser specify the base URL with `KC_URL`:

export KC_URL=http://localhost:8000
export KC_URL=http://localhost:5000
mvn install
npm run serve

Finally, when building the website to be published you need to include `-Dpublish`. This should usually not be done manually though as there is a GitHub Action that takes care of building and publishing to `https://github.com/keycloak/keycloak.github.io`.

Expand Down
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,11 @@
"bootstrap": "5.1.x",
"@fortawesome/fontawesome-free": "5.15.4",
"tocbot": "4.18.0"
},
"scripts": {
"serve": "http-server target/web -c-1 -p 5000 -a 127.0.0.1 --cors"
},
"devDependencies": {
"http-server": "^14.1.1"
}
}
30 changes: 20 additions & 10 deletions pages/404.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,26 @@
<@tmpl.page current="keys" title="Page not found" noindex=true>

<div class="container mt-5">
<h1>Page not found</h1>
<h1 id="heading">Page not found</h1>

<p>
The page you’re looking for does not exist. It may have been moved. You can return to <a href="${links.home}">the start page</a>, or follow one of the links in the navigation on the top.
</p>
<p>
If you arrived at this page by clicking on a link, please notify the owner of the site that the link is broken. If you typed the URL of this page manually, please double-check that you entered the address correctly.
</p>
<div id="notfound">
<p>
The page you’re looking for does not exist. It may have been moved. You can return to <a href="${links.home}">the start page</a>, or follow one of the links in the navigation on the top.
</p>
<p>
If you arrived at this page by clicking on a link, please notify the owner of the site that the link is broken. If you typed the URL of this page manually, please double-check that you entered the address correctly.
</p>

<p>
If you think this is a bug that the Keycloak team should fix, create <a id="buglink" href="https://github.com/keycloak/keycloak-web/issues/new?template=bug.yml&title=Broken%20link%20on%20the%20website%20{url}&description=%0A%0AURL:%20{url}">a bug issue on the GitHub issue tracker</a>.
</p>
<p>
If you think this is a bug that the Keycloak team should fix, create <a id="buglink" href="https://github.com/keycloak/keycloak-web/issues/new?template=bug.yml&title=Broken%20link%20on%20the%20website%20{url}&description=%0A%0AURL:%20{url}">a bug issue on the GitHub issue tracker</a>.
</p>
</div>

<div id="redirecting" style="display: none">
<p>
You are being redirected to <a id="redirectlink" href="...">...</a>.
</p>
</div>

<script>
document.addEventListener("DOMContentLoaded", function() {
Expand All @@ -27,4 +35,6 @@

</div>

<script src="${links.getResource('js/redirect.js')}" type="text/javascript"></script>

</@tmpl.page>
46 changes: 46 additions & 0 deletions resources/js/redirect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
var pageWithHash = window.location.pathname + window.location.hash;
var page = window.location.pathname;
var openRedirects = new XMLHttpRequest();
openRedirects.onreadystatechange = function() {
if (this.readyState === 4 && this.status === 200) {
var redirects = this.responseText.split(/\r?\n/);
for (var i = 0; i < redirects.length; i++) {
var redirect = redirects[i].split("=");
if (redirects[i].trim().startsWith("#")) {
// allow for line comments
continue;
}
var pattern = new RegExp(redirect[0])
if (pattern.test(page) || pattern.test(pageWithHash)) {
document.title = "Redirecting..."
document.getElementById("heading").innerText = "Redirecting...";
document.getElementById("redirecting").style.display = "block";
document.getElementById("notfound").style.display = "none";
document.getElementById("redirectlink").href = redirect[1];
document.getElementById("redirectlink").innerText = redirect[1];
var anchor = "";
if (redirect[1].indexOf("#") !== -1) {
anchor = "#" + redirect[1].split("#")[1];
}
var checkRedirect = new XMLHttpRequest();
checkRedirect.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status === 200) {
// The response URL will no longer contain the anchor, therefore, add it again
window.location = checkRedirect.responseURL + anchor;
} else {
document.getElementById("heading").innerText = "Redirect failed";
document.getElementById("notfound").style.display = "block";
document.getElementById("redirecting").style.display = "none";
}
}
}
checkRedirect.open("GET", redirect[1], true);
checkRedirect.send();
break;
}
}
}
};
openRedirects.open("GET", "/resources/redirects", true);
openRedirects.send();
9 changes: 9 additions & 0 deletions resources/redirects
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Regex with with or without a anchor -> target path
^/docs/(latest|[0-9.]+)/securing_apps=/guides.html#securing-apps
^/docs/(latest|[0-9.]+)/server_installation=/guides.html#server
^/docs/(latest|[0-9.]+)/getting_started=/guides.html#getting-started
^/docs/([0-9.]+)/server-admin=/docs-api/latest/server-admin/index.html
^/docs/([0-9.]+)/upgrading=/docs-api/latest/upgrading/index.html
^/docs-api/[0-9.]+/rest-api=/docs-api/latest/rest-api/index.html
^/[0-9]+/[0-9]+/keycloak-[0-9]+-released=/blog.html
^/404=/
48 changes: 25 additions & 23 deletions src/main/java/org/keycloak/webbuilder/builders/AppBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
Expand All @@ -36,30 +37,31 @@ private void installPackage(String name, String version) throws Exception {
// Get package contents as tarball stream.
Package packageInfo = Registry.getPackage(name);
Version latestVersion = packageInfo.getVersionByTag(version);
ArchiveInputStream<TarArchiveEntry> tarball = latestVersion.getDist().getTarballStream();

// Copy package contents to installation path.
ArchiveEntry entry;
while ((entry = tarball.getNextEntry()) != null) {
// Skip any files not part of the package contents.
String packagePrefix = "package";
if (!entry.getName().startsWith(packagePrefix)) {
continue;
try (ArchiveInputStream<TarArchiveEntry> tarball = latestVersion.getDist().getTarballStream()) {

// Copy package contents to installation path.
ArchiveEntry entry;
while ((entry = tarball.getNextEntry()) != null) {
// Skip any files not part of the package contents.
String packagePrefix = "package";
if (!entry.getName().startsWith(packagePrefix)) {
continue;
}

// Resolve path without 'package' prefix.
Path entryPath = Path.of(packagePrefix).relativize(Path.of(entry.getName()));

// Skip file if it's extension is not permitted.
String extension = getFileExtension(entryPath.getFileName().toString());
if (!ALLOWED_EXTENSIONS.contains(extension)) {
continue;
}

// Resolve target path and copy file.
Path targetPath = installationPath.resolve(entryPath);
Files.createDirectories(targetPath.getParent());
Files.copy(tarball, targetPath, StandardCopyOption.REPLACE_EXISTING);
}

// Resolve path without 'package' prefix.
Path entryPath = Path.of(packagePrefix).relativize(Path.of(entry.getName()));

// Skip file if it's extension is not permitted.
String extension = getFileExtension(entryPath.getFileName().toString());
if(!ALLOWED_EXTENSIONS.contains(extension)) {
continue;
}

// Resolve target path and copy file.
Path targetPath = installationPath.resolve(entryPath);
Files.createDirectories(targetPath.getParent());
Files.copy(tarball, targetPath);
}

// Add package to the imports so it can be written to the import map later.
Expand Down

0 comments on commit 8705691

Please sign in to comment.