From 6203e04c152a109cd7f56ca60d653d5fabdf2dc7 Mon Sep 17 00:00:00 2001 From: Jon Koops Date: Wed, 23 Oct 2024 14:02:33 +0200 Subject: [PATCH] Remove legacy code for older versions of Keycloak JS Closes #500 Signed-off-by: Jon Koops --- pages/app/index.ftl | 7 +- .../java/org/keycloak/webbuilder/Context.java | 6 ++ .../org/keycloak/webbuilder/ImportMap.java | 44 ++++++++++ .../org/keycloak/webbuilder/Versions.java | 5 -- .../org/keycloak/webbuilder/WebBuilder.java | 6 +- .../webbuilder/builders/AppBuilder.java | 51 ------------ .../webbuilder/builders/VendorBuilder.java | 80 +++++++++++++++++++ .../webbuilder/npm/SemanticVersion.java | 44 ---------- .../org/keycloak/webbuilder/npm/Version.java | 16 +--- .../keycloak/webbuilder/utils/FreeMarker.java | 4 +- .../keycloak/webbuilder/utils/JsonParser.java | 8 ++ static/app/app-legacy.js | 79 ------------------ static/app/app.js | 2 +- templates/template.ftl | 1 + 14 files changed, 148 insertions(+), 205 deletions(-) create mode 100644 src/main/java/org/keycloak/webbuilder/ImportMap.java delete mode 100644 src/main/java/org/keycloak/webbuilder/builders/AppBuilder.java create mode 100644 src/main/java/org/keycloak/webbuilder/builders/VendorBuilder.java delete mode 100644 src/main/java/org/keycloak/webbuilder/npm/SemanticVersion.java delete mode 100644 static/app/app-legacy.js diff --git a/pages/app/index.ftl b/pages/app/index.ftl index 168cea5a..a606bec3 100644 --- a/pages/app/index.ftl +++ b/pages/app/index.ftl @@ -2,12 +2,7 @@ <@tmpl.page current="test-app" title="Test application" noindex=true nocsp=true> -<#if version.majorVersion < 26> - - -<#else> - - +
diff --git a/src/main/java/org/keycloak/webbuilder/Context.java b/src/main/java/org/keycloak/webbuilder/Context.java index 8519fb51..476e1d3b 100644 --- a/src/main/java/org/keycloak/webbuilder/Context.java +++ b/src/main/java/org/keycloak/webbuilder/Context.java @@ -31,6 +31,7 @@ public class Context { private Guides guides; private GuidesMetadata guidesMetadata; private News news; + private ImportMap importMap; private FreeMarker freeMarker; private AsciiDoctor asciiDoctor; @@ -66,6 +67,7 @@ public void init() throws Exception { guidesMetadata = new YamlParser().read(new File(getWebSrcDir(),"/guides.yaml"), GuidesMetadata.class); guides = new Guides(guidesMetadata, tmpDir, getWebSrcDir(), asciiDoctor); news = new News(newsDir, blogs, config); + importMap = new ImportMap(tmpDir.toPath()); freeMarker.init(this); asciiDoctor.init(this); @@ -123,6 +125,10 @@ public Links getLinks() { return links; } + public ImportMap getImportMap() { + return importMap; + } + public File getWebSrcDir() { return webSrcDir; } diff --git a/src/main/java/org/keycloak/webbuilder/ImportMap.java b/src/main/java/org/keycloak/webbuilder/ImportMap.java new file mode 100644 index 00000000..c75e17c3 --- /dev/null +++ b/src/main/java/org/keycloak/webbuilder/ImportMap.java @@ -0,0 +1,44 @@ +package org.keycloak.webbuilder; + +import org.keycloak.webbuilder.utils.JsonParser; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; + +public class ImportMap { + private final String FILE_NAME = "import-map.json"; + + private Path targetDir = null; + private String value; + + public ImportMap(Path targetDir) { + this.targetDir = targetDir; + } + + public String getValue() throws Exception { + // Return cached value if present. + if (value != null) { + return value; + } + + // Read import map from disk and cache. + Path source = targetDir.resolve(FILE_NAME); + value = Files.readString(source); + return value; + } + + public void writeValue(Map imports) throws Exception { + // Create target directory if needed. + Files.createDirectories(targetDir); + + // Build import map from installed packages. + Map> importMap = new HashMap<>(); + importMap.put("imports", imports); + + // Write import map to disk. + Path target = targetDir.resolve(FILE_NAME); + JsonParser.write(target.toFile(), importMap); + } +} diff --git a/src/main/java/org/keycloak/webbuilder/Versions.java b/src/main/java/org/keycloak/webbuilder/Versions.java index 9df01fbf..c79ea5b6 100644 --- a/src/main/java/org/keycloak/webbuilder/Versions.java +++ b/src/main/java/org/keycloak/webbuilder/Versions.java @@ -73,11 +73,6 @@ public String getVersionShorter() { return split[0] + "." + split[1]; } - public int getMajorVersion() { - String[] split = version.split("\\."); - return Integer.parseInt(split[0]); - } - public Date getDate() { return date; } diff --git a/src/main/java/org/keycloak/webbuilder/WebBuilder.java b/src/main/java/org/keycloak/webbuilder/WebBuilder.java index 6ced6d32..8ff30516 100644 --- a/src/main/java/org/keycloak/webbuilder/WebBuilder.java +++ b/src/main/java/org/keycloak/webbuilder/WebBuilder.java @@ -1,7 +1,7 @@ package org.keycloak.webbuilder; import org.keycloak.webbuilder.builders.AbstractBuilder; -import org.keycloak.webbuilder.builders.AppBuilder; +import org.keycloak.webbuilder.builders.VendorBuilder; import org.keycloak.webbuilder.builders.BlogBuilder; import org.keycloak.webbuilder.builders.ChangelogBuilder; import org.keycloak.webbuilder.builders.DocumentationArchiveBuilder; @@ -22,6 +22,7 @@ public class WebBuilder { private AbstractBuilder[] builders = new AbstractBuilder[] { // new Cleaner(), + new VendorBuilder(), new ChangelogBuilder(), new ResourcesBuilder(), new ReleaseNotesBuilder(), @@ -31,8 +32,7 @@ public class WebBuilder { new PageBuilder(), new DocumentationArchiveBuilder(), new DownloadsArchiveBuilder(), - new RssFeedBuilder(), - new AppBuilder() + new RssFeedBuilder() }; public static void main(String[] args) throws Exception { diff --git a/src/main/java/org/keycloak/webbuilder/builders/AppBuilder.java b/src/main/java/org/keycloak/webbuilder/builders/AppBuilder.java deleted file mode 100644 index dc005fdb..00000000 --- a/src/main/java/org/keycloak/webbuilder/builders/AppBuilder.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.keycloak.webbuilder.builders; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveInputStream; -import org.apache.commons.compress.archivers.tar.TarArchiveEntry; -import org.apache.commons.io.IOUtils; -import org.keycloak.webbuilder.npm.Package; -import org.keycloak.webbuilder.npm.Registry; -import org.keycloak.webbuilder.npm.Version; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.OutputStream; -import java.nio.file.Path; - -public class AppBuilder extends AbstractBuilder { - - @Override - protected void build() throws Exception { - Package packageInfo = Registry.getPackage("keycloak-js"); - Version latestVersion = packageInfo.getVersionByTag("latest"); - File targetFile = new File(context.getTargetDir(), "app/keycloak.js"); - - // Skip if target file already exists. - if (targetFile.isFile()) { - return; - } - - boolean useLegacy = latestVersion.getSemanticVersion().getMajor() < 26; - String entryPoint = latestVersion.resolveEntryPoint(useLegacy); - String sourcePath = Path.of("package", entryPoint).normalize().toString(); - ArchiveInputStream tarball = latestVersion.getDist().getTarballStream(); - - for (ArchiveEntry entry = tarball.getNextEntry(); entry != null; entry = tarball.getNextEntry()) { - // Loop trough until we find a file that matches the package entrypoint. - if (!entry.getName().equals(sourcePath)) { - continue; - } - - // Copy the file over when found. - try (OutputStream outputStream = new FileOutputStream(targetFile)) { - IOUtils.copy(tarball, outputStream); - } - } - } - - @Override - protected String getTitle() { - return "App"; - } -} diff --git a/src/main/java/org/keycloak/webbuilder/builders/VendorBuilder.java b/src/main/java/org/keycloak/webbuilder/builders/VendorBuilder.java new file mode 100644 index 00000000..ef3de665 --- /dev/null +++ b/src/main/java/org/keycloak/webbuilder/builders/VendorBuilder.java @@ -0,0 +1,80 @@ +package org.keycloak.webbuilder.builders; + +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.ArchiveInputStream; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.keycloak.webbuilder.npm.Package; +import org.keycloak.webbuilder.npm.Registry; +import org.keycloak.webbuilder.npm.Version; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class VendorBuilder extends AbstractBuilder { + private final Set ALLOWED_EXTENSIONS = Set.of("js"); + + private final Map imports = new HashMap<>(); + + @Override + protected void build() throws Exception { + // Install packages. + installPackage("keycloak-js", "latest"); + // Write import map to disk. + context.getImportMap().writeValue(imports); + } + + private void installPackage(String name, String version) throws Exception { + // Resolve installation path and create directories. + Path installationPath = context.getTargetDir().toPath().resolve("vendor").resolve(name); + Files.createDirectories(installationPath); + + // Get package contents as tarball stream. + Package packageInfo = Registry.getPackage(name); + Version latestVersion = packageInfo.getVersionByTag(version); + ArchiveInputStream 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); + } + + // Add package to the imports so it can be written to the import map later. + Path importPath = Path.of("/vendor", name, latestVersion.resolveEntryPoint()).normalize(); + imports.put(name, importPath.toString()); + } + + private String getFileExtension(String filename) { + int dotIndex = filename.lastIndexOf("."); + if (dotIndex >= 0) { + return filename.substring(dotIndex + 1); + } + return ""; + } + + @Override + protected String getTitle() { + return "Vendor"; + } +} diff --git a/src/main/java/org/keycloak/webbuilder/npm/SemanticVersion.java b/src/main/java/org/keycloak/webbuilder/npm/SemanticVersion.java deleted file mode 100644 index 0a453db2..00000000 --- a/src/main/java/org/keycloak/webbuilder/npm/SemanticVersion.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.keycloak.webbuilder.npm; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class SemanticVersion { - private static final Pattern VERSION_PATTERN = Pattern.compile("^(\\d+)\\.(\\d+)\\.(\\d+)$"); - - private final int major; - private final int minor; - private final int patch; - - private SemanticVersion(int major, int minor, int patch) { - this.major = major; - this.minor = minor; - this.patch = patch; - } - - public int getMajor() { - return major; - } - - public int getMinor() { - return minor; - } - - public int getPatch() { - return patch; - } - - public static SemanticVersion fromString(String versionString) { - Matcher matcher = VERSION_PATTERN.matcher(versionString); - - if (!matcher.matches()) { - return null; - } - - int major = Integer.parseInt(matcher.group(1)); - int minor = Integer.parseInt(matcher.group(2)); - int patch = Integer.parseInt(matcher.group(3)); - - return new SemanticVersion(major, minor, patch); - } -} diff --git a/src/main/java/org/keycloak/webbuilder/npm/Version.java b/src/main/java/org/keycloak/webbuilder/npm/Version.java index 52418c1e..c0e3a1c6 100644 --- a/src/main/java/org/keycloak/webbuilder/npm/Version.java +++ b/src/main/java/org/keycloak/webbuilder/npm/Version.java @@ -14,31 +14,17 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class Version { - @JsonProperty("version") - private String version; - - @JsonProperty("main") - private String main; - @JsonProperty("exports") private Map exports; @JsonProperty("dist") private Dist dist; - public SemanticVersion getSemanticVersion() { - return SemanticVersion.fromString(version); - } - public Dist getDist() { return dist; } - public String resolveEntryPoint(boolean useLegacy) { - if (useLegacy) { - return main; - } - + public String resolveEntryPoint() { Export defaultExport = exports.get("."); return defaultExport != null ? defaultExport.getDefaultPath() : null; } diff --git a/src/main/java/org/keycloak/webbuilder/utils/FreeMarker.java b/src/main/java/org/keycloak/webbuilder/utils/FreeMarker.java index 87ef69d1..59fd376d 100644 --- a/src/main/java/org/keycloak/webbuilder/utils/FreeMarker.java +++ b/src/main/java/org/keycloak/webbuilder/utils/FreeMarker.java @@ -69,7 +69,7 @@ public void writeFile(Map attr, String template, File targetDir, downloadTemplate.process(attributes, out); } - public void init(Context context) { + public void init(Context context) throws Exception { globalAttributes = new HashMap<>(); String root = context.config().isPublish() ? context.config().getUrls().getHome() : context.getTargetDir().toURI().toString(); @@ -97,6 +97,8 @@ public void init(Context context) { globalAttributes.put("links", context.getLinks()); + globalAttributes.put("importMap", context.getImportMap()); + isPublish = context.config().isPublish(); targetDir = context.getTargetDir(); } diff --git a/src/main/java/org/keycloak/webbuilder/utils/JsonParser.java b/src/main/java/org/keycloak/webbuilder/utils/JsonParser.java index 3f93d913..c9de065e 100644 --- a/src/main/java/org/keycloak/webbuilder/utils/JsonParser.java +++ b/src/main/java/org/keycloak/webbuilder/utils/JsonParser.java @@ -27,4 +27,12 @@ public static T read(URL url, Class t) { } } + public static void write(File f, Object v) { + try { + mapper.writeValue(f, v); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } diff --git a/static/app/app-legacy.js b/static/app/app-legacy.js deleted file mode 100644 index 81ed41c1..00000000 --- a/static/app/app-legacy.js +++ /dev/null @@ -1,79 +0,0 @@ -function init() { - document.getElementById('config-form').onsubmit = function() { - updateConfig(); - return false; - } - - var conf = loadConfig(); - - if (conf.url && conf.realm && conf.client) { - var keycloak = new Keycloak({ - url: conf.url, - realm: conf.realm, - clientId: conf.client - }); - - keycloak.init({ - checkLoginIframe: false - }).then(function(auth) { - document.getElementById('login').onclick = keycloak.login; - document.getElementById('logout').onclick = keycloak.logout; - - show('config-view'); - hide('config-edit'); - - if (auth) { - var name; - if (keycloak.tokenParsed['family_name'] || keycloak.tokenParsed['given_name']) { - name = keycloak.tokenParsed['given_name'] + ' ' + keycloak.tokenParsed['family_name'] - } else { - name = keycloak.tokenParsed.preferred_username; - } - document.getElementById('user-details').innerHTML = name; - hide('login'); - show('logout') - show('display-user'); - - } else { - console.info('Not Authenticated'); - hide('display-user'); - show('login'); - hide('logout') - } - }) - } else { - show('config-edit'); - hide('config-view'); - } -} - -function show(id) { - document.getElementById(id).classList.remove('hide'); - document.getElementById(id).classList.add('show'); -} - -function hide(id) { - document.getElementById(id).classList.add('hide'); - document.getElementById(id).classList.remove('show'); -} - -function updateConfig() { - var url = document.getElementById('url').value; - var realm = document.getElementById('realm').value; - var client = document.getElementById('client').value; - - window.location.href = window.location.href.split('#')[0] + '#url=' + url + '&realm=' + realm + '&client=' + client; -} - -function loadConfig() { - var h = window.location.hash.substring(1).split('&'); - var r = {}; - for (var i = 0; i < h.length; i++) { - var t = h[i].split('=') - r[t[0]] = t[1]; - } - return r; -} - -window.onhashchange = init; -window.onload = init; \ No newline at end of file diff --git a/static/app/app.js b/static/app/app.js index 551d251d..2d36bb1e 100644 --- a/static/app/app.js +++ b/static/app/app.js @@ -1,4 +1,4 @@ -import Keycloak from './keycloak.js'; +import Keycloak from 'keycloak-js'; function init() { document.getElementById('config-form').onsubmit = function() { diff --git a/templates/template.ftl b/templates/template.ftl index 5e04c040..1c55d5fd 100644 --- a/templates/template.ftl +++ b/templates/template.ftl @@ -21,6 +21,7 @@ +