/* * The contents of this file are subject to the terms of the Common Development and * Distribution License (the License). You may not use this file except in compliance with the * License. * * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions Copyright [year] [name of copyright owner]". * * Copyright 2006-2009 Sun Microsystems, Inc. * Portions Copyright 2014-2016 ForgeRock AS. */ package com.forgerock.opendj.ldap.tools; import static com.forgerock.opendj.cli.CliMessages.ERR_FILEARG_NO_SUCH_FILE; import static com.forgerock.opendj.cli.CommonArguments.showUsageArgument; import static com.forgerock.opendj.cli.ToolVersionHandler.newSdkVersionHandler; import static com.forgerock.opendj.cli.Utils.throwIfArgumentsConflict; import static com.forgerock.opendj.ldap.CoreMessages.ERR_BASE64_DECODE_INVALID_LENGTH; import static com.forgerock.opendj.ldap.tools.LDAPToolException.newToolException; import static com.forgerock.opendj.ldap.tools.LDAPToolException.newToolExceptionAlreadyPrinted; import static com.forgerock.opendj.ldap.tools.LDAPToolException.newToolParamException; import static com.forgerock.opendj.ldap.tools.ToolsMessages.*; import static com.forgerock.opendj.ldap.tools.Utils.parseArguments; import static com.forgerock.opendj.ldap.tools.Utils.runToolAndExit; import static com.forgerock.opendj.util.StaticUtils.getExceptionMessage; import static org.forgerock.util.Utils.closeSilently; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import com.forgerock.opendj.cli.ArgumentException; import com.forgerock.opendj.cli.BooleanArgument; import com.forgerock.opendj.cli.StringArgument; import com.forgerock.opendj.cli.SubCommand; import com.forgerock.opendj.cli.SubCommandArgumentParser; import org.forgerock.opendj.ldap.ResultCode; import org.forgerock.util.annotations.VisibleForTesting; /** * Tool that can be used for performing base64 encoding and decoding. *

* Base64 is a mechanism for encoding binary data in ASCII form by converting * sets of three bytes with eight significant bits each to sets of four bytes * with six significant bits each. */ public final class Base64 extends ToolConsoleApplication { /** * The main method for base64 tool. * * @param args * The command-line arguments provided to this program. */ public static void main(final String[] args) { runToolAndExit(new Base64(System.out, System.err), args); } @VisibleForTesting Base64(final PrintStream out, final PrintStream err) { super(out, err); } @Override public boolean isInteractive() { return false; } @Override int run(final String... args) throws LDAPToolException { final SubCommandArgumentParser argParser = new SubCommandArgumentParser(Base64.class.getName(), INFO_BASE64_TOOL_DESCRIPTION.get(), false); argParser.setShortToolDescription(REF_SHORT_DESC_BASE64.get()); argParser.setVersionHandler(newSdkVersionHandler()); final BooleanArgument showUsage; final SubCommand decodeSubCommand; final StringArgument encodedData; final StringArgument encodedFile; final StringArgument toRawFile; final SubCommand encodeSubCommand; final StringArgument rawData; final StringArgument rawFile; final StringArgument toEncodedFile; try { decodeSubCommand = new SubCommand(argParser, "decode", INFO_BASE64_DECODE_DESCRIPTION.get()); encodeSubCommand = new SubCommand(argParser, "encode", INFO_BASE64_ENCODE_DESCRIPTION.get()); encodedData = StringArgument.builder("encodedData") .shortIdentifier('d') .description(INFO_BASE64_ENCODED_DATA_DESCRIPTION.get()) .valuePlaceholder(INFO_DATA_PLACEHOLDER.get()) .buildAndAddToSubCommand(decodeSubCommand); encodedFile = StringArgument.builder("encodedDataFile") .shortIdentifier('f') .description(INFO_BASE64_ENCODED_FILE_DESCRIPTION.get()) .valuePlaceholder(INFO_PATH_PLACEHOLDER.get()) .buildAndAddToSubCommand(decodeSubCommand); toRawFile = StringArgument.builder("toRawFile") .shortIdentifier('o') .description(INFO_BASE64_TO_RAW_FILE_DESCRIPTION.get()) .valuePlaceholder(INFO_PATH_PLACEHOLDER.get()) .buildAndAddToSubCommand(decodeSubCommand); rawData = StringArgument.builder("rawData") .shortIdentifier('d') .description(INFO_BASE64_RAW_DATA_DESCRIPTION.get()) .valuePlaceholder(INFO_DATA_PLACEHOLDER.get()) .buildAndAddToSubCommand(encodeSubCommand); rawFile = StringArgument.builder("rawDataFile") .shortIdentifier('f') .description(INFO_BASE64_RAW_FILE_DESCRIPTION.get()) .valuePlaceholder(INFO_PATH_PLACEHOLDER.get()) .buildAndAddToSubCommand(encodeSubCommand); toEncodedFile = StringArgument.builder("toEncodedFile") .shortIdentifier('o') .description(INFO_BASE64_TO_ENCODED_FILE_DESCRIPTION.get()) .valuePlaceholder(INFO_PATH_PLACEHOLDER.get()) .buildAndAddToSubCommand(encodeSubCommand); final List subCommandList = new ArrayList<>(2); subCommandList.add(decodeSubCommand); subCommandList.add(encodeSubCommand); showUsage = showUsageArgument(); argParser.addGlobalArgument(showUsage); argParser.setUsageGroupArgument(showUsage, subCommandList); argParser.setUsageArgument(showUsage, getOutputStream()); } catch (final ArgumentException ae) { throw newToolParamException(ae, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); } parseArguments(argParser, getErrStream(), args); if (argParser.usageOrVersionDisplayed()) { return ResultCode.SUCCESS.intValue(); } try { throwIfArgumentsConflict(encodedData, encodedFile); throwIfArgumentsConflict(rawData, rawFile); } catch (final ArgumentException e) { argParser.displayMessageAndUsageReference(getErrStream(), ERR_ERROR_PARSING_ARGS.get(e.getMessage())); throw newToolParamException(e, e.getMessageObject()); } final SubCommand subCommand = argParser.getSubCommand(); if (subCommand == null) { argParser.displayMessageAndUsageReference(getErrStream(), ERR_BASE64_NO_SUBCOMMAND_SPECIFIED.get()); throw newToolExceptionAlreadyPrinted(null, ResultCode.CLIENT_SIDE_PARAM_ERROR); } if (subCommand.getName().equals(encodeSubCommand.getName())) { return encode(rawData, rawFile, toEncodedFile); } else if (subCommand.getName().equals(decodeSubCommand.getName())) { return decode(encodedData, encodedFile, toRawFile); } else { argParser.displayMessageAndUsageReference( getErrStream(), ERR_BASE64_UNKNOWN_SUBCOMMAND.get(subCommand.getName())); throw newToolExceptionAlreadyPrinted(null, ResultCode.CLIENT_SIDE_PARAM_ERROR); } } private int encode(final StringArgument rawDataArg, final StringArgument rawDataFilePathArg, final StringArgument toEncodeFilePathArg) throws LDAPToolException { byte[] dataToEncode; if (rawDataArg.isPresent()) { try { dataToEncode = rawDataArg.getValue().getBytes("UTF-8"); } catch (final UnsupportedEncodingException e) { throw newToolException(e, ResultCode.OPERATIONS_ERROR, ERR_BASE64_ERROR_DECODING_RAW_DATA.get(e.getMessage())); } } else { final boolean readFromFile = rawDataFilePathArg.isPresent(); InputStream inputStream = null; final String rawDataFilePath = rawDataFilePathArg.getValue(); try { inputStream = readFromFile ? new FileInputStream(rawDataFilePath) : getInputStream(); final ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) >= 0) { baos.write(buffer, 0, bytesRead); } dataToEncode = baos.toByteArray(); } catch (final FileNotFoundException e) { throw newToolParamException( e, ERR_FILEARG_NO_SUCH_FILE.get(rawDataFilePath, rawDataFilePathArg.getLongIdentifier())); } catch (final Exception e) { throw newToolException(e, ResultCode.OPERATIONS_ERROR, ERR_BASE64_CANNOT_READ_RAW_DATA.get(getExceptionMessage(e))); } finally { if (readFromFile) { closeSilently(inputStream); } } } final String base64Data = org.forgerock.util.encode.Base64.encode(dataToEncode); if (toEncodeFilePathArg.isPresent()) { try (final BufferedWriter writer = new BufferedWriter(new FileWriter(toEncodeFilePathArg.getValue()))) { writer.write(base64Data); writer.newLine(); } catch (final Exception e) { throw newToolException(e, ResultCode.OPERATIONS_ERROR, ERR_BASE64_CANNOT_WRITE_ENCODED_DATA.get(getExceptionMessage(e))); } } else { getOutputStream().println(base64Data); } return ResultCode.SUCCESS.intValue(); } private int decode(final StringArgument encodedDataArg, final StringArgument encodedDataFilePathArg, final StringArgument toRawFilePathArg) throws LDAPToolException { String dataToDecode = null; if (encodedDataArg.isPresent()) { dataToDecode = encodedDataArg.getValue(); } else { final boolean readFromFile = encodedDataFilePathArg.isPresent(); BufferedReader reader = null; final String encodedDataFilePath = encodedDataFilePathArg.getValue(); try { reader = new BufferedReader(readFromFile ? new FileReader(encodedDataFilePath) : new InputStreamReader(System.in)); final StringBuilder buffer = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { final StringTokenizer tokenizer = new StringTokenizer(line); while (tokenizer.hasMoreTokens()) { buffer.append(tokenizer.nextToken()); } } dataToDecode = buffer.toString(); } catch (final FileNotFoundException e) { throw newToolParamException( e, ERR_FILEARG_NO_SUCH_FILE.get(encodedDataFilePath, encodedDataFilePathArg.getLongIdentifier())); } catch (final Exception e) { throw newToolException(e, ResultCode.OPERATIONS_ERROR, ERR_BASE64_CANNOT_READ_ENCODED_DATA.get(getExceptionMessage(e))); } finally { if (readFromFile) { closeSilently(reader); } } } if (dataToDecode.length() % 4 != 0) { throw newToolParamException(ERR_BASE64_DECODE_INVALID_LENGTH.get(dataToDecode)); } final byte[] decodedData = org.forgerock.util.encode.Base64.decode(dataToDecode); if (decodedData == null) { throw newToolParamException(ERR_BASE64_ERROR_DECODING_RAW_DATA.get(dataToDecode)); } try { if (toRawFilePathArg.isPresent()) { try (final FileOutputStream outputStream = new FileOutputStream(toRawFilePathArg.getValue())) { outputStream.write(decodedData); } } else { try (final PrintStream outputPrintStream = getOutputStream()) { outputPrintStream.write(decodedData); } } } catch (final Exception e) { throw newToolException(e, ResultCode.OPERATIONS_ERROR, ERR_BASE64_CANNOT_WRITE_RAW_DATA.get(getExceptionMessage(e))); } return ResultCode.SUCCESS.intValue(); } }