diff --git a/add-on/build.gradle b/add-on/build.gradle index 1a0f8de..fd33427 100644 --- a/add-on/build.gradle +++ b/add-on/build.gradle @@ -10,10 +10,7 @@ configurations { canBeConsumed = true canBeResolved = false } - nativeApp { - canBeConsumed = false - canBeResolved = true - } + nativeApp.extendsFrom runtime } /** @@ -21,7 +18,9 @@ configurations { */ interface ExtensionData { Property getName() + Property getDescription() + Property getId() } @@ -30,14 +29,117 @@ extension.name = "universalmusic" extension.description = "A link between the Universal Music Player and the web browser." extension.id = "universalmusic@regis.edu" +/** + * Creates an addon manifest for running + */ +abstract class BuildManifest extends DefaultTask { + @OutputFile + final abstract RegularFileProperty manifests = project.objects.fileProperty() + + @TaskAction + void join() { + println "Making build directories!" + String addonName = project.extension.name.get(), addonDescription = project.extension.description.get(), extensionId = project.extension.id.get() + File manifest + File startupScript + for (Dependency dep : project.configurations.nativeApp.dependencies) { + File binFiles = new File(dep.dependencyProject.installDist.outputs.getFiles().getSingleFile(), "bin") + Stream files = Arrays.stream(binFiles.listFiles()) + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + startupScript = files.filter(file -> file.getName().endsWith(".bat")).findFirst().get() + } else if (Os.isFamily(Os.FAMILY_UNIX)) { + startupScript = files.filter(file -> !file.getName().endsWith(".sh")).findFirst().get() + } else { + throw new RuntimeException("Unknown OS family") + } + manifests.get().asFile.text = "{\n" + + " \"name\": \"$addonName\",\n" + + " \"description\": \"$addonDescription\",\n" + + " \"path\": \"" + startupScript.getAbsolutePath().replace("\\", "\\\\") + "\",\n" + + " \"type\": \"stdio\",\n" + + " \"allowed_extensions\": [\"$extensionId\"]\n" + + "}" + break + } + } + +} + +/** + * + */ +abstract class InstallAddon extends DefaultTask { + @InputFile + @SkipWhenEmpty + final abstract RegularFileProperty inputFile = project.objects.fileProperty() + + @TaskAction + void join() { + File file = inputFile.get().asFile + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + String name = file.name.substring(0, file.name.lastIndexOf('.')) + Process p = Runtime.getRuntime() + .exec("REG DELETE HKEY_CURRENT_USER\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\${name} /f ") + p.waitFor() + p = Runtime.getRuntime() + .exec("REG ADD HKEY_CURRENT_USER\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\${name} /ve /d \"" + + file.getAbsolutePath() + "\" /f ") + p.waitFor() + } else if (Os.isFamily(Os.FAMILY_MAC)) { + Files.copy(file.toPath(), Paths.get(System.getProperty("user.home"), "Library/Application Support/Mozilla/NativeMessagingHosts", file.getName()), StandardCopyOption.REPLACE_EXISTING) + } else if (Os.isFamily(Os.FAMILY_UNIX)) { + Files.copy(file.toPath(), Paths.get(System.getProperty("user.home"), ".mozilla/native-messaging-hosts", file.getName()), StandardCopyOption.REPLACE_EXISTING) + } + } +} + +dependencies { + nativeApp project(path: ":addonInter", configuration: 'nativeBuild') +} + +tasks.register('buildManifest', BuildManifest) { + manifests = new File(buildDir, "${extension.name.get()}.json") +} + +def installAddon = tasks.register('installAddon', InstallAddon) { + inputFile = buildManifest.manifests +} + /** * Creates a packaged (albiet unsigned) Firefox addon from the src/main directory. */ tasks.register('zipAddon', Zip) { + dependsOn configurations.nativeApp archiveName = "${extension.id.get()}.xpi" destinationDir = file("$buildDir/lib") from("$projectDir/src/addon/javascript", "$projectDir/src/addon/resources") + doLast { + File profiles + File extention + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + profiles = new File(System.getenv("APPDATA"), "Mozilla\\Firefox\\Profiles") + } else if (Os.isFamily(Os.FAMILY_MAC)) { + profiles = new File(System.getProperty("user.home"), "Library/Application Support/Firefox/Profiles") + } else if (Os.isFamily(Os.FAMILY_UNIX)) { + profiles = new File(System.getProperty("user.home"), ".mozilla/firefox/") + } + for (File profile: profiles.listFiles()) + { + if (profile.isDirectory()) + { + extention = new File(profile, "extensions/${extension.id.get()}.xpi") + if (extention.exists()) + { + copy { + from(zipAddon.outputs) + into extention.getParentFile() + } + } + } + } + } } +zipAddon.finalizedBy installAddon tasks.register("clean", Delete) { delete "$buildDir" diff --git a/addonInter/build.gradle b/addonInter/build.gradle index f41a1e4..ae6b74c 100644 --- a/addonInter/build.gradle +++ b/addonInter/build.gradle @@ -16,9 +16,9 @@ plugins { } configurations { - addon { - canBeConsumed = false - canBeResolved = true + nativeBuild { + canBeConsumed = true + canBeResolved = false } } @@ -30,84 +30,6 @@ repositories { } } -/** - * Creates an addon manifest for running - */ -abstract class BuildManifest extends DefaultTask { - @InputDirectory - final abstract DirectoryProperty inputFile = project.objects.directoryProperty() - @OutputDirectory - final abstract DirectoryProperty manifestDir = project.objects.directoryProperty().convention(project.layout.buildDirectory.dir("manifests")) - @OutputFiles - final abstract FileCollection manifests = project.objects.fileCollection() - - @TaskAction - void join() { - manifestDir.get().asFile.mkdir() - println "Making build directories!" - String addonName, addonDescription, extensionId - File manifest - File startupScript - File binFiles = new File(inputFile.get().asFile, "bin") - Stream files = Arrays.stream(binFiles.listFiles()) - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - startupScript = files.filter(file -> file.getName().endsWith(".bat")).findFirst().get() - } else if (Os.isFamily(Os.FAMILY_UNIX)) { - startupScript = files.filter(file -> !file.getName().endsWith(".sh")).findFirst().get() - } else { - throw new RuntimeException("Unknown OS family") - } - HashSet manifestSet = new HashSet<>() - for (Dependency dep : project.configurations.addon.dependencies) { - addonName = dep.dependencyProject.extension.name.get() - addonDescription = dep.dependencyProject.extension.description.get() - extensionId = dep.dependencyProject.extension.id.get() - manifest = manifestDir.get().file("${addonName}.json").asFile - manifest.createNewFile() - println manifest - manifest.text = "{\n" + - " \"name\": \"$addonName\",\n" + - " \"description\": \"$addonDescription\",\n" + - " \"path\": \"" + startupScript.getAbsolutePath().replace("\\", "\\\\") + "\",\n" + - " \"type\": \"stdio\",\n" + - " \"allowed_extensions\": [\"$extensionId\"]\n" + - "}" - manifestSet.add(manifest) - } - manifests.setFrom(manifestSet) - println manifests.files - } -} - -/** - * - */ -abstract class InstallAddon extends DefaultTask { - @InputDirectory - final abstract DirectoryProperty inputFile = project.objects.directoryProperty() - - @TaskAction - void join() { -// File file = inputFile.get().asFile - for (File file: inputFile.asFileTree) { - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - String name = file.name.substring(0, file.name.lastIndexOf('.')) - Process p = Runtime.getRuntime() - .exec("REG DELETE HKEY_CURRENT_USER\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\${name} /f ") - p.waitFor() - p = Runtime.getRuntime() - .exec("REG ADD HKEY_CURRENT_USER\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\${name} /ve /d \"" - + file.getAbsolutePath() + "\" /f ") - p.waitFor() - } else if (Os.isFamily(Os.FAMILY_MAC)) { - Files.copy(file.toPath(), Paths.get(System.getProperty("user.home"), "Library/Application Support/Mozilla/NativeMessagingHosts", file.getName()), StandardCopyOption.REPLACE_EXISTING) - } else if (Os.isFamily(Os.FAMILY_UNIX)) { - Files.copy(file.toPath(), Paths.get(System.getProperty("user.home"), ".mozilla/native-messaging-hosts", file.getName()), StandardCopyOption.REPLACE_EXISTING) - } - } - } -} - // In this section you declare the dependencies for your production and test code dependencies { implementation 'org.slf4j:slf4j-api:1.7.30' @@ -126,19 +48,13 @@ dependencies { // testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add // 'test.useTestNG()' to your build script. testImplementation 'junit:junit:4.12' - - addon(project(":add-on")) } -tasks.register('buildManifest', BuildManifest) { - dependsOn installDist - inputFile = installDist.outputs.getFiles().getSingleFile() -} - -tasks.register('installAddon', InstallAddon) { - inputFile = buildManifest.manifestDir -} -assemble.dependsOn(installAddon) - // Define the main class for the application mainClassName = defaultPackage + '.addon.Main' + +artifacts { + nativeBuild(installDist.destinationDir) { + builtBy installDist + } +} \ No newline at end of file diff --git a/browser/browserConf/distribution/policies.json b/browser/browserConf/distribution/policies.json index 2a095e9..cc28f49 100644 --- a/browser/browserConf/distribution/policies.json +++ b/browser/browserConf/distribution/policies.json @@ -15,6 +15,9 @@ "Fingerprinting": true }, "DontCheckDefaultBrowser": true, + "ExtensionSettings": { + ${preinstalled} + }, "Permissions": { "Camera": { "BlockNewRequests": true diff --git a/browser/build.gradle b/browser/build.gradle index b292ad5..4220c76 100644 --- a/browser/build.gradle +++ b/browser/build.gradle @@ -217,6 +217,22 @@ task movePolicies(type: Copy) { dependsOn setupProfile from files("browserConf") into "$rootDir/firefox/" + filesMatching('**/policies.json'){ + def pre = "" + for (File addon: configurations.addon.resolve()) + { + if (pre.length() > 0) + { + pre += ",\n" + } + pre += "\"" + addon.name.substring(0, addon.name.lastIndexOf('.')) + "\": {\n" + pre += "\"installation_mode\": \"forced_install\"," + pre += "\"install_url\": \"" + addon.toURI().toString() + "\"" + pre += "}" + } + println "Expanding ${pre}" + expand(preinstalled: pre) + } doLast { println "Making policies firefox!" } diff --git a/browser/src/main/java/edu/regis/universeplayer/browser/Browser.java b/browser/src/main/java/edu/regis/universeplayer/browser/Browser.java index 3695384..770b286 100644 --- a/browser/src/main/java/edu/regis/universeplayer/browser/Browser.java +++ b/browser/src/main/java/edu/regis/universeplayer/browser/Browser.java @@ -8,7 +8,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.io.FileWriter; import java.io.IOException; +import java.io.PrintStream; import java.net.ConnectException; import java.net.InetAddress; import java.net.ServerSocket; @@ -22,31 +24,32 @@ import edu.regis.universeplayer.browserCommands.MessageRunner; public class Browser extends MessageRunner { private static final Logger logger = LoggerFactory.getLogger(Browser.class); - + private static Browser INSTANCE; private static final AtomicBoolean instanceWaiter = new AtomicBoolean(); - + public static Browser getInstance() { return INSTANCE; } - + private final Process process; private final ServerSocket server; private final Socket socket; - + private boolean running = true; - + public static Browser createBrowser() throws IOException, InterruptedException { if (INSTANCE != null) { return INSTANCE; } - - ServerSocket server = new ServerSocket(BrowserConstants.PORT, 50, InetAddress.getByName(null)); + + ServerSocket server = new ServerSocket(BrowserConstants.PORT, 50, InetAddress + .getByName(null)); logger.debug("Server started."); - + int startExit; Process browserProcess = launchBrowser(); /* @@ -58,7 +61,8 @@ public class Browser extends MessageRunner if (startExit != 0) { logger.error("Error in browser launch (exit code {})", startExit); - try (Scanner scanner = new Scanner(browserProcess.getErrorStream())) + try (Scanner scanner = new Scanner(browserProcess + .getErrorStream())) { while (scanner.hasNextLine()) { @@ -69,7 +73,7 @@ public class Browser extends MessageRunner } } logger.debug("Browser started."); - + ConnectException connErr = null; logger.debug("Attempting connection"); Socket socket = server.accept(); @@ -102,26 +106,28 @@ public class Browser extends MessageRunner notifyAllInstance(); return INSTANCE; } - + private Browser(Socket socket, ServerSocket server, Process process) throws IOException { - super("BrowserRunner", socket.getInputStream(), socket.getOutputStream()); + super("BrowserRunner", socket.getInputStream(), socket + .getOutputStream()); this.socket = socket; this.server = server; this.process = process; } - + @Override protected boolean onRun() { - if (!socket.isConnected() || socket.isClosed() || socket.isInputShutdown() || socket.isOutputShutdown()) + if (!socket.isConnected() || socket.isClosed() || socket + .isInputShutdown() || socket.isOutputShutdown()) { logger.debug("Socket closed, shutting down"); return true; } return !this.running; } - + @Override protected void onClose() { @@ -150,55 +156,64 @@ public class Browser extends MessageRunner } } } - + /** * Utility method for launching a browser instance * - * @throws IOException - Thrown if there is a problem launching the browser. + * @throws IOException - Thrown if there is a problem launching the + * browser. */ - private static Process launchBrowser() throws IOException + private static Process launchBrowser() throws IOException, InterruptedException { Process process = null; String os = System.getProperty("os.name").toLowerCase(); String arch = System.getProperty("os.arch").toLowerCase(); String args; File browserDir = new File(System.getProperty("user.dir"), "firefox"); - File profileDir = new File(System.getProperty("user.dir"), "profile"); - profileDir.mkdir(); if (!browserDir.isDirectory()) { - /* - * For some reason, the above maps to the interface project module, rather than the root project. - */ - browserDir = new File(new File(System.getProperty("user.dir")).getParent(), "firefox"); + browserDir = new File(new File(System.getProperty("user.dir")) + .getParent(), "firefox"); } - -// args = " -profile \"" + profileDir.getAbsolutePath() + "\""; - args = ""; - System.out.println(profileDir); + File profileDir = new File(System.getProperty("user.dir"), "profile"); + if (!profileDir.exists()) + { + profileDir.mkdir(); + } + +// args = " -no-remote -profile \"" + profileDir.getAbsolutePath() + "\""; + args = " -no-remote -P Universal"; logger.info("Running on {} {}", os, arch); // System.getProperties().entrySet().stream().forEach(entry -> logger.info("{}: {}", entry.getKey(), entry.getValue())); + File firefox = null; if (os.contains("windows")) { - process = Runtime.getRuntime().exec(new File(browserDir, "firefox.exe").getAbsolutePath() + args); + firefox = new File(browserDir, "firefox.exe"); } else if (os.contains("linux")) { - process = Runtime.getRuntime().exec(new File(browserDir, "firefox").getAbsolutePath() + args); + firefox = new File(browserDir, "firefox"); + } + if (firefox != null) + { + firefox = firefox.getAbsoluteFile(); + Runtime.getRuntime().exec(firefox + " -CreateProfile Universal").waitFor(); + process = Runtime.getRuntime().exec(firefox + .getAbsolutePath() + args); } if (process == null) { throw new IOException("Could not find Firefox installation for OS " + os + " " + arch); } - + return process; } - + public static void notifyInstance() { instanceWaiter.notify(); } - + public static void notifyAllInstance() { synchronized (instanceWaiter) @@ -206,7 +221,7 @@ public class Browser extends MessageRunner instanceWaiter.notifyAll(); } } - + public static void waitInstance() throws InterruptedException { synchronized (instanceWaiter) @@ -214,7 +229,7 @@ public class Browser extends MessageRunner instanceWaiter.wait(); } } - + public static void waitInstance(long timeoutMillis) throws InterruptedException { synchronized (instanceWaiter) @@ -222,7 +237,7 @@ public class Browser extends MessageRunner instanceWaiter.wait(timeoutMillis); } } - + public static void waitInstance(long timeoutMillis, int nanos) throws InterruptedException { synchronized (instanceWaiter)