5061 allow Bing Translator credentials to be set by user

This commit is contained in:
William Schaefer 2019-05-28 18:08:24 -04:00
parent 85a3124f9d
commit 1408fd289b
7 changed files with 368 additions and 17 deletions

View File

@ -19,12 +19,20 @@
package org.sleuthkit.autopsy.texttranslation.translators;
import java.io.*;
import com.google.gson.*;
import com.squareup.okhttp.*;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import java.awt.Component;
import javax.swing.JLabel;
import java.io.IOException;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.texttranslation.TextTranslator;
import org.sleuthkit.autopsy.texttranslation.TranslationException;
/**
* Translates text by making HTTP requests to Bing Translator.
@ -32,13 +40,13 @@ import org.openide.util.NbBundle.Messages;
*/
@ServiceProvider(service = TextTranslator.class)
public class BingTranslator implements TextTranslator{
// Insert the subscription key here.
private String subscriptionKey = "";
//In the String below, "en" is the target language. You can include multiple target
//languages separated by commas. A full list of supported languages is here:
//https://docs.microsoft.com/en-us/azure/cognitive-services/translator/language-support
private static final String URL = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=en";
private final BingTranslatorSettingsPanel settingsPanel;
private final BingTranslatorSettings settings = new BingTranslatorSettings();
// This sends messages to Microsoft.
private final OkHttpClient CLIENT = new OkHttpClient();
@ -47,6 +55,15 @@ public class BingTranslator implements TextTranslator{
//paid account that's willing to pay for long documents.
private final int MAX_STRING_LENGTH = 5000;
public BingTranslator(){
settingsPanel = new BingTranslatorSettingsPanel(settings.getCredentials());
}
static String getMicrosftTranlatorUrl(){
return URL;
}
/**
* Converts an input test to the JSON format required by Bing Translator,
* posts it to Microsoft, and returns the JSON text response.
@ -68,7 +85,7 @@ public class BingTranslator implements TextTranslator{
bodyString);
Request request = new Request.Builder()
.url(URL).post(body)
.addHeader("Ocp-Apim-Subscription-Key", subscriptionKey)
.addHeader("Ocp-Apim-Subscription-Key", settings.getCredentials())
.addHeader("Content-type", "application/json").build();
Response response = CLIENT.newCall(request).execute();
return response.body().string();
@ -76,7 +93,7 @@ public class BingTranslator implements TextTranslator{
@Override
public String translate(String string) throws TranslationException {
if (subscriptionKey == null || subscriptionKey.isEmpty()) {
if (settings.getCredentials() == null || settings.getCredentials().isEmpty()) {
throw new TranslationException("Bing Translator has not been configured, credentials need to be specified");
}
@ -111,17 +128,12 @@ public class BingTranslator implements TextTranslator{
@Override
public Component getComponent() {
return new JLabel("There are no settings to configure for Bing Translator");
return settingsPanel;
}
@Override
public void saveSettings() {
//There are no settings to configure for Bing Translator
//Possible settings for the future:
//source language, target language, API key, path to JSON file of API key.
//We'll need test code to make sure that exceptions are thrown in all of
//those scenarios.
return;
settings.setCredentials(settingsPanel.getCredentials());
}
private String parseJSONResponse(String json_text) throws TranslationException {

View File

@ -0,0 +1,80 @@
/*
* Autopsy
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.texttranslation.translators;
import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
/**
* Class to handle the settings associated with the GoogleTranslator
*/
public final class BingTranslatorSettings {
private static final String CREDENTIALS_KEY = "Credentials";
private static final String BING_TRANSLATE_NAME = "BingTranslate";
private static final String DEFAULT_CREDENTIALS = "";
private String credentials;
/**
* Construct a new GoogleTranslatorSettingsObject
*/
BingTranslatorSettings() {
loadSettings();
}
/**
* Get the path to the JSON credentials file
*
* @return the path to the credentials file
*/
String getCredentials() {
return credentials;
}
/**
* Set the path to the JSON credentials file
*
* @param path the path to the credentials file
*/
void setCredentials(String creds) {
credentials = creds;
}
/**
* Load the settings into memory from their on disk storage
*/
void loadSettings() {
if (!ModuleSettings.configExists(BING_TRANSLATE_NAME)) {
ModuleSettings.makeConfigFile(BING_TRANSLATE_NAME);
}
if (ModuleSettings.settingExists(BING_TRANSLATE_NAME, CREDENTIALS_KEY)) {
credentials = ModuleSettings.getConfigSetting(BING_TRANSLATE_NAME, CREDENTIALS_KEY);
} else {
credentials = DEFAULT_CREDENTIALS;
}
}
/**
* Save the setting from memory to their location on disk
*/
void saveSettings() {
ModuleSettings.setConfigSetting(BING_TRANSLATE_NAME, CREDENTIALS_KEY, credentials);
}
}

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="warningLabel" min="-2" pref="551" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="credentialsLabel" min="-2" pref="86" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="credentialsField" pref="463" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="testButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="credentialsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="credentialsField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="testButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="31" max="-2" attributes="0"/>
<Component id="warningLabel" min="-2" pref="18" max="-2" attributes="0"/>
<EmptySpace pref="29" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="credentialsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties" key="GoogleTranslatorSettingsPanel.credentialsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="credentialsField">
</Component>
<Component class="javax.swing.JLabel" name="warningLabel">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties" key="GoogleTranslatorSettingsPanel.warningLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="testButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties" key="BingTranslatorSettingsPanel.testButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="testButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,171 @@
/*
* Autopsy
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.texttranslation.translators;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import com.google.gson.JsonObject;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import java.io.IOException;
import java.util.logging.Logger;
/**
* Settings panel for the GoogleTranslator
*/
public class BingTranslatorSettingsPanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(BingTranslatorSettingsPanel.class.getName());
private static final long serialVersionUID = 1L;
/**
* Creates new form GoogleTranslatorSettingsPanel
*/
public BingTranslatorSettingsPanel(String credentials) {
initComponents();
credentialsField.setText(credentials);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
credentialsLabel = new javax.swing.JLabel();
credentialsField = new javax.swing.JTextField();
warningLabel = new javax.swing.JLabel();
testButton = new javax.swing.JButton();
org.openide.awt.Mnemonics.setLocalizedText(credentialsLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.credentialsLabel.text")); // NOI18N
warningLabel.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(warningLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.warningLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(testButton, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.testButton.text")); // NOI18N
testButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
testButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addComponent(credentialsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(credentialsField, javax.swing.GroupLayout.DEFAULT_SIZE, 463, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(testButton)
.addGap(8, 8, 8))))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(credentialsLabel)
.addComponent(credentialsField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(testButton))
.addGap(31, 31, 31)
.addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(29, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
private void testButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_testButtonActionPerformed
if (testTranslationSetup()) {
warningLabel.setText("");
} else {
warningLabel.setText("Invalid translation credentials");
}
}//GEN-LAST:event_testButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTextField credentialsField;
private javax.swing.JLabel credentialsLabel;
private javax.swing.JButton testButton;
private javax.swing.JLabel warningLabel;
// End of variables declaration//GEN-END:variables
/**
* Converts an input test to the JSON format required by Bing Translator,
* posts it to Microsoft, and returns the JSON text response.
*
* @param string The input text to be translated.
*
* @return The translation response as a JSON string
*
* @throws IOException if the request could not be executed due to
* cancellation, a connectivity problem or timeout.
*/
private boolean testTranslationSetup() {
String testString = "forense";
MediaType mediaType = MediaType.parse("application/json");
JsonArray jsonArray = new JsonArray();
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("Text", testString);
jsonArray.add(jsonObject);
String bodyString = jsonArray.toString();
RequestBody body = RequestBody.create(mediaType,
bodyString);
Request request = new Request.Builder()
.url(BingTranslator.getMicrosftTranlatorUrl()).post(body)
.addHeader("Ocp-Apim-Subscription-Key", credentialsField.getText())
.addHeader("Content-type", "application/json").build();
try {
Response response = new OkHttpClient().newCall(request).execute();
JsonParser parser = new JsonParser();
JsonArray responses = parser.parse(response.body().string()).getAsJsonArray();
//As far as I know, there's always exactly one item in the array.
JsonObject response0 = responses.get(0).getAsJsonObject();
JsonArray translations = response0.getAsJsonArray("translations");
JsonObject translation0 = translations.get(0).getAsJsonObject();
translation0.get("text").getAsString();
return true;
} catch (IOException | IllegalStateException | ClassCastException | NullPointerException | IndexOutOfBoundsException e) {
return false;
}
}
/**
* Get the currently set path to the JSON credentials file
*
* @return the path to the credentials file specified in the textarea
*/
String getCredentials() {
return credentialsField.getText();
}
}

View File

@ -2,3 +2,4 @@ GoogleTranslatorSettingsPanel.browseButton.text=Browse
GoogleTranslatorSettingsPanel.credentialsLabel.text=Credentials:
GoogleTranslatorSettingsPanel.warningLabel.text=
GoogleTranslatorSettingsPanel.targetLanguageLabel.text=Target Language:
BingTranslatorSettingsPanel.testButton.text=Test

View File

@ -1,3 +1,4 @@
BingTranslator.name.text=Bing Translator
GoogleTranslator.name.text=Google Translate
GoogleTranslatorSettingsPanel.browseButton.text=Browse
GoogleTranslatorSettingsPanel.credentialsLabel.text=Credentials:
@ -11,3 +12,4 @@ GoogleTranslatorSettingsPanel.fileChooser.confirmButton=Select
GoogleTranslatorSettingsPanel.json.description=JSON Files
GoogleTranslatorSettingsPanel.warningLabel.text=
GoogleTranslatorSettingsPanel.targetLanguageLabel.text=Target Language:
BingTranslatorSettingsPanel.jButton1.text=Test

View File

@ -106,7 +106,7 @@ public final class GoogleTranslator implements TextTranslator {
}
/**
* Load the Google Cloud Translation service give the currently saved
* Load the Google Cloud Translation service given the currently saved
* settings
*/
private void loadTranslator() {