/* * Copyright (C) 2009-2017 Alistair Neil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package lib; import java.awt.Desktop; import java.awt.FontMetrics; import java.awt.Frame; import java.awt.event.WindowEvent; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.ArrayList; import java.util.Formatter; import java.util.Random; import java.util.regex.Pattern; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JTable; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.filechooser.FileFilter; /** * * @author Alistair Neil */ public final class Utilities { /** * Constructor */ public Utilities() { } /** * Covert list to csv * * @param al * @return String of comma separated values */ public static String getListAsCSV(ArrayList al) { return al.toString().replace("[", "").replace("]", "").replace(" ", ""); } /** * Preloads filechooser in background so it will open instantly when * requested */ public static void preloadFileChooser() { Thread t = new Thread(new java.lang.Runnable() { @Override public void run() { JFileChooser fileChooser = new JFileChooser(); } }); t.start(); } /** * Opens java file chooser dialog, convenience method. Returns filepath if * successful and null if not * * @param parent * @param folder * @param filter Extension filter * @param mode Fileselection mode * @return String Filepath */ public static String openFileChooser(Frame parent, String folder, FileFilter filter, int mode) { JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode(mode); fileChooser.setCurrentDirectory(new File(folder)); if (filter != null) { fileChooser.addChoosableFileFilter(filter); } int intReturn = fileChooser.showOpenDialog(parent); if (intReturn == JFileChooser.APPROVE_OPTION) { return fileChooser.getSelectedFile().getAbsolutePath(); } else { return null; } } /** * Check for newer appversion * * @param localversion * @param remoteversion * @return True if newer */ public static boolean isNewerVersion(String localversion, String remoteversion) { return convertBuildnumToFloat(remoteversion) > convertBuildnumToFloat(localversion); } /** * Convert an debian build number into a floating point number * * @param version * @return Float version */ private static float convertBuildnumToFloat(String version) { float result; Pattern p; String[] parts; try { if (version.contains("-")) { // Handling for old non-debian compatible version p = Pattern.compile("-"); parts = p.split(version); } else { // Handling for new debian compatible version p = Pattern.compile("\\."); parts = p.split(version); parts[0] = parts[0] + "." + parts[1]; parts[1] = parts[2]; parts[2] = ""; } result = Float.parseFloat(parts[0]); result += (Float.parseFloat(parts[1]) / 100000); } catch (Exception ex) { version = version.replaceAll("[^0-9.]", ""); result = convertVersionToFloat(version); } return result; } /** * Convert a windows version number into a floating point number * * @param version * @return Float version */ private static float convertVersionToFloat(String version) { int c; float f; version = version.toLowerCase(); if (version.startsWith("v")) { version = version.substring(1); } try { c = version.charAt(version.length() - 1); if (c > 96) { version = version.substring(0, version.length() - 1); Float fraction = (float) (c - 96) / 10000; f = Float.parseFloat(version) + fraction; } else { f = Float.parseFloat(version); } } catch (Exception ex) { f = 0; } return f; } /** * Open the desktop default file editor * * @param path Path to file */ public static void editFile(String path) { if (OSFunction.isLinux()) { OSFunction.launchProcess("xdg-open", path); return; } if (OSFunction.isWindows()) { OSFunction.launchProcess("notepad", path); } } /** * Launch the desktops default file handling program * * @param strUrl * @return Returns true if successful */ public static boolean openFileExternally(final String strUrl) { String url = strUrl.replace("\\", "/"); try { if (OSFunction.isLinux()) { OSFunction.launchProcess("xdg-open", url); } else { if (Desktop.isDesktopSupported()) { Desktop deskSupport = Desktop.getDesktop(); if (url.startsWith("http") || url.startsWith("ftp")) { deskSupport.browse(new URI(url)); } else { deskSupport.open(new File(url)); } } } return true; } catch (URISyntaxException | IOException ex) { } return false; } /** * Initialises the UI Look and Feel * * @param theme */ public static void loadUIStyle(String theme) { try { if (theme == null) { UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); return; } if (theme.contentEquals("Metal")) { UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); return; } if (theme.contentEquals("Nimbus")) { // Switch to Nimbus theme UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); return; } if (theme.contentEquals("System")) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); return; } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); return; } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } // If everything else fails use default cross platform metal try { UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } } /** * Adjust specified column width based on the width of a test string * * @param table * @param test */ public static void adjustTableColumnWidth(JTable table, String... test) { FontMetrics ourFontMetrics = table.getFontMetrics(table.getFont()); int col = 0; for (String s : test) { table.getColumn(table.getColumnName(col++)).setPreferredWidth(ourFontMetrics.stringWidth(s)); } } /** * Generate secret key. * * @param length * @return String key */ public static String generateSecretKey(int length) { StringBuilder buffer = new StringBuilder(); Random random = new Random(); String chars = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int x; try { for (int i = 0; i < length; i++) { x = random.nextInt(chars.length() - 1); buffer.append(chars.substring(x, x + 1)); } } catch (Exception ex) { } return buffer.toString(); } public static String getTorHashPassword(String secret) { byte[] key = S2KRFC2440(secret); return "16:" + byteToHex(key); } /** * Secret to key, Algorithm info taken from * http://sunsite.icm.edu.pl/gnupg/rfc2440-3.html * * @param secret * @return hashed key for the given secret */ public static byte[] S2KRFC2440(String secret) { // Create our message digest for SHA-1 MessageDigest md; try { md = MessageDigest.getInstance("SHA-1"); } catch (Exception ex) { return null; } // Create our random S2K salt, the 9th byte is loaded with the code count which // determines the amount of octet hashing used. // This salt is eventually combined with the secret to prevent dictionary attacks int codecount = 32; byte[] s2ksalt = new byte[9]; SecureRandom sr = new SecureRandom(); sr.nextBytes(s2ksalt); s2ksalt[8] = (byte) codecount; // The octet hashing count is defined by the following formula where EXPBIAS is 6 int octethashcount = (16 + (codecount & 15)) << ((codecount >> 4) + 6); // Merge our S2K salt and partialsecret arrays together into one array to // create the full secret key. byte[] partialsecret; try { partialsecret = secret.getBytes("UTF-8"); } catch (UnsupportedEncodingException ex) { return null; } byte[] fullsecret = new byte[8 + partialsecret.length]; System.arraycopy(s2ksalt, 0, fullsecret, 0, 8); System.arraycopy(partialsecret, 0, fullsecret, 8, partialsecret.length); // Do the hashing based on the hashcount while (true) { if (octethashcount < fullsecret.length) { md.update(fullsecret, 0, octethashcount); break; } else { md.update(fullsecret); } octethashcount -= fullsecret.length; } // Create our final key by merging s2kspecifier and digest result byte[] ourkey = new byte[20 + 9]; System.arraycopy(md.digest(), 0, ourkey, 9, 20); System.arraycopy(s2ksalt, 0, ourkey, 0, 9); return ourkey; } /** * Get SHAHash using given password string * * @param password * @return SHAhash string */ public static String getSHAHash(String password) { String sha1 = ""; try { MessageDigest crypt = MessageDigest.getInstance("SHA-1"); crypt.reset(); crypt.update(password.getBytes("UTF-8")); sha1 = byteToHex(crypt.digest()); } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { } return sha1; } /** * Convert byte to a hex string * * @param hash * @return byte as a hex string */ private static String byteToHex(final byte[] hash) { String result; try (Formatter formatter = new Formatter()) { for (byte b : hash) { formatter.format("%02x", b); } result = formatter.toString(); } return result; } /** * Retrieve text from a resource text file * * @param resourcepath * @return String text */ public static String getTextFromResource(String resourcepath) { SimpleFile sf = new SimpleFile(resourcepath); sf.openBufferedResource(); String text = sf.readEntireFile(); sf.closeFile(); return text; } /** * Retrieve text from a text file * * @param filepath * @return String text */ public static String getTextFromFile(String filepath) { SimpleFile sf = new SimpleFile(filepath); String text = ""; if (sf.exists()) { sf.openBufferedRead(); text = sf.readEntireFile(); sf.closeFile(); } return text; } /** * Calculate the sha1 checksum of a given file * * @param filepath * @return Checksum as a hex string */ public static String getSha1Sum(String filepath) { StringBuilder sb = new StringBuilder(""); try { MessageDigest md = MessageDigest.getInstance("SHA1"); FileInputStream fis = new FileInputStream(filepath); byte[] dataBytes = new byte[1024]; int nread; while ((nread = fis.read(dataBytes)) != -1) { md.update(dataBytes, 0, nread); } byte[] mdbytes = md.digest(); //convert the byte to hex format for (int i = 0; i < mdbytes.length; i++) { sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1)); } } catch (NoSuchAlgorithmException | IOException ex) { } return sb.toString(); } /** * Creates a hidden dummy window for registration to various docks/launchers * Fixes the neverending launching indicator */ public static void registerWindow() { final JFrame jf = new JFrame(); jf.addWindowListener(new java.awt.event.WindowListener() { @Override public void windowOpened(WindowEvent e) { jf.dispose(); } @Override public void windowClosing(WindowEvent e) { } @Override public void windowClosed(WindowEvent e) { } @Override public void windowIconified(WindowEvent e) { } @Override public void windowDeiconified(WindowEvent e) { } @Override public void windowActivated(WindowEvent e) { } @Override public void windowDeactivated(WindowEvent e) { } }); jf.setUndecorated(true); jf.setBounds(0, 0, 0, 0); jf.setVisible(true); } }