mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
Merge remote-tracking branch 'origin/GP-5167_ghidra1_BSimUsername--SQUASHED'
This commit is contained in:
commit
e07aa499ea
34 changed files with 1097 additions and 429 deletions
|
@ -26,7 +26,7 @@ import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.features.base.values.GhidraValuesMap;
|
import ghidra.features.base.values.GhidraValuesMap;
|
||||||
import ghidra.features.bsim.query.*;
|
import ghidra.features.bsim.query.*;
|
||||||
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
||||||
import ghidra.features.bsim.query.FunctionDatabase.Error;
|
import ghidra.features.bsim.query.FunctionDatabase.BSimError;
|
||||||
import ghidra.features.bsim.query.FunctionDatabase.ErrorCategory;
|
import ghidra.features.bsim.query.FunctionDatabase.ErrorCategory;
|
||||||
import ghidra.features.bsim.query.description.DatabaseInformation;
|
import ghidra.features.bsim.query.description.DatabaseInformation;
|
||||||
import ghidra.features.bsim.query.description.DescriptionManager;
|
import ghidra.features.bsim.query.description.DescriptionManager;
|
||||||
|
@ -71,8 +71,7 @@ public class AddProgramToH2BSimDatabaseScript extends GhidraScript {
|
||||||
askValues("Select Database File", null, values);
|
askValues("Select Database File", null, values);
|
||||||
|
|
||||||
File h2DbFile = values.getFile(DATABASE);
|
File h2DbFile = values.getFile(DATABASE);
|
||||||
BSimServerInfo serverInfo =
|
BSimServerInfo serverInfo = new BSimServerInfo(h2DbFile.getAbsolutePath());
|
||||||
new BSimServerInfo(DBType.file, null, 0, h2DbFile.getAbsolutePath());
|
|
||||||
|
|
||||||
BSimH2FileDataSource existingBDS =
|
BSimH2FileDataSource existingBDS =
|
||||||
BSimH2FileDBConnectionManager.getDataSourceIfExists(serverInfo);
|
BSimH2FileDBConnectionManager.getDataSourceIfExists(serverInfo);
|
||||||
|
@ -129,7 +128,7 @@ public class AddProgramToH2BSimDatabaseScript extends GhidraScript {
|
||||||
InsertRequest insertreq = new InsertRequest();
|
InsertRequest insertreq = new InsertRequest();
|
||||||
insertreq.manage = manager;
|
insertreq.manage = manager;
|
||||||
if (insertreq.execute(h2Database) == null) {
|
if (insertreq.execute(h2Database) == null) {
|
||||||
Error lastError = h2Database.getLastError();
|
BSimError lastError = h2Database.getLastError();
|
||||||
if ((lastError.category == ErrorCategory.Format) ||
|
if ((lastError.category == ErrorCategory.Format) ||
|
||||||
(lastError.category == ErrorCategory.Nonfatal)) {
|
(lastError.category == ErrorCategory.Nonfatal)) {
|
||||||
Msg.showWarn(this, null, "Skipping Insert",
|
Msg.showWarn(this, null, "Skipping Insert",
|
||||||
|
|
|
@ -25,7 +25,7 @@ import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.features.base.values.GhidraValuesMap;
|
import ghidra.features.base.values.GhidraValuesMap;
|
||||||
import ghidra.features.bsim.query.*;
|
import ghidra.features.bsim.query.*;
|
||||||
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
||||||
import ghidra.features.bsim.query.FunctionDatabase.Error;
|
import ghidra.features.bsim.query.FunctionDatabase.BSimError;
|
||||||
import ghidra.features.bsim.query.description.DatabaseInformation;
|
import ghidra.features.bsim.query.description.DatabaseInformation;
|
||||||
import ghidra.features.bsim.query.file.BSimH2FileDBConnectionManager;
|
import ghidra.features.bsim.query.file.BSimH2FileDBConnectionManager;
|
||||||
import ghidra.features.bsim.query.file.BSimH2FileDBConnectionManager.BSimH2FileDataSource;
|
import ghidra.features.bsim.query.file.BSimH2FileDBConnectionManager.BSimH2FileDataSource;
|
||||||
|
@ -89,8 +89,7 @@ public class CreateH2BSimDatabaseScript extends GhidraScript {
|
||||||
List<String> cats = parseCSV(exeCatCSV);
|
List<String> cats = parseCSV(exeCatCSV);
|
||||||
|
|
||||||
File dbFile = new File(dbDir, databaseName);
|
File dbFile = new File(dbDir, databaseName);
|
||||||
BSimServerInfo serverInfo =
|
BSimServerInfo serverInfo = new BSimServerInfo(dbFile.getAbsolutePath());
|
||||||
new BSimServerInfo(DBType.file, null, 0, dbFile.getAbsolutePath());
|
|
||||||
|
|
||||||
BSimH2FileDataSource existingBDS =
|
BSimH2FileDataSource existingBDS =
|
||||||
BSimH2FileDBConnectionManager.getDataSourceIfExists(serverInfo);
|
BSimH2FileDBConnectionManager.getDataSourceIfExists(serverInfo);
|
||||||
|
@ -118,7 +117,7 @@ public class CreateH2BSimDatabaseScript extends GhidraScript {
|
||||||
req.tag_name = tag;
|
req.tag_name = tag;
|
||||||
ResponseInfo resp = req.execute(h2Database);
|
ResponseInfo resp = req.execute(h2Database);
|
||||||
if (resp == null) {
|
if (resp == null) {
|
||||||
Error lastError = h2Database.getLastError();
|
BSimError lastError = h2Database.getLastError();
|
||||||
throw new LSHException(lastError.message);
|
throw new LSHException(lastError.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +127,7 @@ public class CreateH2BSimDatabaseScript extends GhidraScript {
|
||||||
req.type_name = cat;
|
req.type_name = cat;
|
||||||
ResponseInfo resp = req.execute(h2Database);
|
ResponseInfo resp = req.execute(h2Database);
|
||||||
if (resp == null) {
|
if (resp == null) {
|
||||||
Error lastError = h2Database.getLastError();
|
BSimError lastError = h2Database.getLastError();
|
||||||
throw new LSHException(lastError.message);
|
throw new LSHException(lastError.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -130,7 +130,7 @@ public class QueryWithFiltersScript extends GhidraScript {
|
||||||
String dbUrl =
|
String dbUrl =
|
||||||
askString("", "Enter the URL of the BSim database:", "ghidra://localhost/bsimDb");
|
askString("", "Enter the URL of the BSim database:", "ghidra://localhost/bsimDb");
|
||||||
queryService.initializeDatabase(dbUrl);
|
queryService.initializeDatabase(dbUrl);
|
||||||
FunctionDatabase.Error error = queryService.getLastError();
|
FunctionDatabase.BSimError error = queryService.getLastError();
|
||||||
if (error != null && error.category == ErrorCategory.Nodatabase) {
|
if (error != null && error.category == ErrorCategory.Nodatabase) {
|
||||||
println("Database [" + dbUrl + "] cannot be found (does it exist?)");
|
println("Database [" + dbUrl + "] cannot be found (does it exist?)");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -326,7 +326,12 @@
|
||||||
<DD>
|
<DD>
|
||||||
<P>Creates a new empty repository. A URL and configuration template (<SPAN class=
|
<P>Creates a new empty repository. A URL and configuration template (<SPAN class=
|
||||||
"bold"><STRONG>config_template</STRONG></SPAN>) is required. The new database name
|
"bold"><STRONG>config_template</STRONG></SPAN>) is required. The new database name
|
||||||
is taken from the path element of the URL.</P>
|
is taken from the path element of the URL. See <A class="xref" href=
|
||||||
|
"DatabaseConfiguration.html#CreateDatabase" title="Creating a Database">“Creating a
|
||||||
|
Database”</A> for more details and discussion on configuration template use.
|
||||||
|
See <A class="xref" href="DatabaseConfiguration.html#DatabaseTemplates"
|
||||||
|
title="Creating Database Templates">“Creating Database Templates“</A>
|
||||||
|
if a standard template will not suffice.</P>
|
||||||
|
|
||||||
<P>Supported configuration templates (<SPAN class=
|
<P>Supported configuration templates (<SPAN class=
|
||||||
"bold"><STRONG>config_template</STRONG></SPAN>) are defined within the Ghidra
|
"bold"><STRONG>config_template</STRONG></SPAN>) are defined within the Ghidra
|
||||||
|
@ -792,21 +797,21 @@
|
||||||
<TD>PostgreSQL</TD>
|
<TD>PostgreSQL</TD>
|
||||||
|
|
||||||
<TD><CODE class=
|
<TD><CODE class=
|
||||||
"computeroutput">postgresql://<hostname>[:<port>]/<dbname></CODE></TD>
|
"computeroutput">postgresql://[<username>@]<hostname>[:<port>]/<dbname></CODE></TD>
|
||||||
</TR>
|
</TR>
|
||||||
|
|
||||||
<TR>
|
<TR>
|
||||||
<TD>Elasticsearch</TD>
|
<TD>Elasticsearch</TD>
|
||||||
|
|
||||||
<TD><CODE class=
|
<TD><CODE class=
|
||||||
"computeroutput">https://<hostname>[:<port>]/<dbname></CODE></TD>
|
"computeroutput">https://[<username>@]<hostname>[:<port>]/<dbname></CODE></TD>
|
||||||
</TR>
|
</TR>
|
||||||
|
|
||||||
<TR>
|
<TR>
|
||||||
<TD>Elasticsearch</TD>
|
<TD>Elasticsearch</TD>
|
||||||
|
|
||||||
<TD><CODE class=
|
<TD><CODE class=
|
||||||
"computeroutput">elastic://<hostname>[:<port>]/<dbname></CODE></TD>
|
"computeroutput">elastic://[<username>@]<hostname>[:<port>]/<dbname></CODE></TD>
|
||||||
</TR>
|
</TR>
|
||||||
|
|
||||||
<TR>
|
<TR>
|
||||||
|
@ -819,6 +824,24 @@
|
||||||
</DIV>
|
</DIV>
|
||||||
|
|
||||||
<P>The use of the <EM>https</EM> and <EM>elastic</EM> is equivalent.</P>
|
<P>The use of the <EM>https</EM> and <EM>elastic</EM> is equivalent.</P>
|
||||||
|
|
||||||
|
<P><IMG border="0" src="help/shared/tip.png" alt="Tip: ">The inclusion of a
|
||||||
|
<CODE class="computeroutput"><username></CODE> within a BSim URL
|
||||||
|
supercedes the concurrent use of the <SPAN class="command"><STRONG>--user</STRONG></SPAN>
|
||||||
|
option which can still be used to control login to the Ghidra Server. When a
|
||||||
|
<CODE class="computeroutput"><username></CODE> has been specified within a BSim URL
|
||||||
|
a <CODE class="computeroutput"><password></CODE> may be included if neccessary,
|
||||||
|
albeit highly discouraged (e.g.,
|
||||||
|
<CODE class="computeroutput">postgresql://username:password@hostname/dbname</CODE>).
|
||||||
|
The password is appended to the username with a colon (':') separator and has limitations
|
||||||
|
on the characters which may be used.</P>
|
||||||
|
|
||||||
|
<P><IMG border="0" src="images/warning.help.png" alt="Warning: ">Inclusion of a user
|
||||||
|
<CODE class="computeroutput"><password></CODE> within a BSim URL is highly
|
||||||
|
discouraged and only intended for use within restricted environments since the URL entry will persist
|
||||||
|
within the system process table and possibly within system log files. This may be useful
|
||||||
|
in controlled situations where console password prompts cannot be handled. Handling
|
||||||
|
the password prompt is preferred.</P>
|
||||||
|
|
||||||
<P>For local <EM>file</EM> URLs, the absolute path the H2 database <EM>*.mv.db</EM> file
|
<P>For local <EM>file</EM> URLs, the absolute path the H2 database <EM>*.mv.db</EM> file
|
||||||
must be specified without the <EM>*.mv.db</EM> extension. Only the '/' character should be
|
must be specified without the <EM>*.mv.db</EM> extension. Only the '/' character should be
|
||||||
|
|
|
@ -527,6 +527,34 @@
|
||||||
that are different from the standard PostgreSQL defaults. To provide site specific
|
that are different from the standard PostgreSQL defaults. To provide site specific
|
||||||
configuration, changes should be made to the normal PostgreSQL configuration files.</P>
|
configuration, changes should be made to the normal PostgreSQL configuration files.</P>
|
||||||
</DIV>
|
</DIV>
|
||||||
|
|
||||||
|
<DIV class="sect3">
|
||||||
|
<DIV class="titlepage">
|
||||||
|
<DIV>
|
||||||
|
<DIV>
|
||||||
|
<H4 class="title"><A name="PostgresFirewall"></A>PostgreSQL Firewall Considerations</H4>
|
||||||
|
</DIV>
|
||||||
|
</DIV>
|
||||||
|
</DIV>
|
||||||
|
|
||||||
|
<P>Remote client access to the PostgreSQL server may have network firewalls
|
||||||
|
which must be considered and properly configured to allow network access.
|
||||||
|
Both dedicated network firewalls and OS-level firewalls must be considered.</P>
|
||||||
|
|
||||||
|
<P>Firewall configurations are beyond the scope of this document, however for simple
|
||||||
|
single-node installations on Linux the <CODE class="computeroutput">firewall-cmd</CODE>
|
||||||
|
may be used to allow incoming connections to the appropriate port (TCP port 5432 is the
|
||||||
|
default for PostgreSQL). This does not consider network firewall devices which may
|
||||||
|
also impact connectivity.</P>
|
||||||
|
|
||||||
|
<PRE><CODE class "computeroutput">
|
||||||
|
sudo firewall-cmd --permanent --add-port=5432/tcp && sudo firewall-cmd --reload
|
||||||
|
</CODE></PRE>
|
||||||
|
|
||||||
|
<P>NOTE: The above Linux firewall command assumes the <CODE class="computeroutput">firewalld</CODE>
|
||||||
|
package has been installed on the system.</P>
|
||||||
|
|
||||||
|
</DIV>
|
||||||
</DIV>
|
</DIV>
|
||||||
|
|
||||||
<DIV class="sect2">
|
<DIV class="sect2">
|
||||||
|
@ -562,13 +590,22 @@
|
||||||
|
|
||||||
<P>In order to make use of Elasticsearch with BSim, the database administrator must
|
<P>In order to make use of Elasticsearch with BSim, the database administrator must
|
||||||
install the <SPAN class="emphasis"><EM>lsh.zip</EM></SPAN> plug-in as part of the
|
install the <SPAN class="emphasis"><EM>lsh.zip</EM></SPAN> plug-in as part of the
|
||||||
Elasticsearch deployment. The plug-in is available in the Ghidra add-on named <SPAN
|
Elasticsearch deployment. The plug-in is available in the Ghidra extension named <SPAN
|
||||||
class="emphasis"><EM>BSimElasticPlugin</EM></SPAN>, which unpacks into a standard
|
class="emphasis"><EM>BSimElasticPlugin</EM></SPAN>
|
||||||
Ghidra installation. The file <SPAN class="emphasis"><EM>lsh.zip</EM></SPAN> is a
|
(<CODE class="computeroutput"><ghidra-install-dir>/Extensions/Ghidra/ghidra_11.2.1_U_20241105_BSimElasticPlugin.zip</CODE>).
|
||||||
standard Elasticsearch plug-in that must be installed on every node of the cluster
|
The extension may be unzipped to a temporary location or use Ghidra's Install Extensions
|
||||||
|
capability which will unpack it into the users platform-specific config directory
|
||||||
|
indicated in the detail view of the Install Extensions window. The extension is not
|
||||||
|
used directly by Ghidra and is only needed for the
|
||||||
|
<SPAN class="emphasis"><EM>lsh.zip</EM></SPAN> elasticsearch plug-in
|
||||||
|
which must be installed on every node of the cluster
|
||||||
before a BSim repository can be created. The description below shows how to enable
|
before a BSim repository can be created. The description below shows how to enable
|
||||||
the BSim plug-in for a single node, but this will need to be repeated for any
|
the BSim plug-in for a single node, but this will need to be repeated for any
|
||||||
additional nodes.</P>
|
additional nodes.</P>
|
||||||
|
|
||||||
|
<P><IMG border="0" src="help/shared/tip.png" alt="Tip: ">Refer to the <I>README.md</I>
|
||||||
|
file within the unpacked extension for important plugin details. The plugin file
|
||||||
|
stipulates a specific elasticsearch version and may require an adjustment and repack.</P>
|
||||||
|
|
||||||
<P>Assuming the add-on has been unpacked, the plug-in can be installed to a single node
|
<P>Assuming the add-on has been unpacked, the plug-in can be installed to a single node
|
||||||
using the <SPAN class="emphasis"><EM>elasticsearch-plugin</EM></SPAN> command in the
|
using the <SPAN class="emphasis"><EM>elasticsearch-plugin</EM></SPAN> command in the
|
||||||
|
@ -579,7 +616,7 @@
|
||||||
<TABLE border="0" summary="Simple list" class="simplelist">
|
<TABLE border="0" summary="Simple list" class="simplelist">
|
||||||
<TR>
|
<TR>
|
||||||
<TD><CODE class="computeroutput">bin/elasticsearch-plugin install
|
<TD><CODE class="computeroutput">bin/elasticsearch-plugin install
|
||||||
file:///path/to/ghidra/Ghidra/contrib/BSimElasticPlugin/data/lsh.zip</CODE></TD>
|
file:///path/to/ghidra/extension/BSimElasticPlugin/data/lsh.zip</CODE></TD>
|
||||||
</TR>
|
</TR>
|
||||||
</TABLE>
|
</TABLE>
|
||||||
</DIV>
|
</DIV>
|
||||||
|
@ -610,7 +647,7 @@
|
||||||
</DIV>
|
</DIV>
|
||||||
</DIV>
|
</DIV>
|
||||||
|
|
||||||
<P>The open Elasticsearch distribution starts with up with password authentication
|
<P>The open Elasticsearch distribution starts with password authentication
|
||||||
enabled by default. When a node is started up for the first time, as described above, an
|
enabled by default. When a node is started up for the first time, as described above, an
|
||||||
<SPAN class="bold"><STRONG>elastic</STRONG></SPAN> user is created with a randomly
|
<SPAN class="bold"><STRONG>elastic</STRONG></SPAN> user is created with a randomly
|
||||||
generated password that is reported, once, to the console. For a toy deployment, it may
|
generated password that is reported, once, to the console. For a toy deployment, it may
|
||||||
|
@ -665,6 +702,34 @@ curl -k -u elastic:XXXXXX -X POST "https://localhost:9200/_security/user/ghidrau
|
||||||
class="xref" href="CommandLineReference.html#URLs">“Ghidra and BSim
|
class="xref" href="CommandLineReference.html#URLs">“Ghidra and BSim
|
||||||
URLs”</A> for additional information about URLs.</P>
|
URLs”</A> for additional information about URLs.</P>
|
||||||
</DIV>
|
</DIV>
|
||||||
|
|
||||||
|
<DIV class="sect3">
|
||||||
|
<DIV class="titlepage">
|
||||||
|
<DIV>
|
||||||
|
<DIV>
|
||||||
|
<H4 class="title"><A name="ElasticFirewall"></A>Elasticsearch Firewall Considerations</H4>
|
||||||
|
</DIV>
|
||||||
|
</DIV>
|
||||||
|
</DIV>
|
||||||
|
|
||||||
|
<P>Remote client access to the Elasticsearch server/cluster may have network firewalls
|
||||||
|
which must be considered and properly configured to allow network access.
|
||||||
|
Both dedicated network firewalls and OS-level firewalls must be considered.</P>
|
||||||
|
|
||||||
|
<P>Firewall configurations are beyond the scope of this document, however for simple
|
||||||
|
single-node installations on Linux the <CODE class="computeroutput">firewall-cmd</CODE>
|
||||||
|
may be used to allow incoming connections to the appropriate port (TCP port 9200 is the
|
||||||
|
default for elasticsearch). This does not consider network firewall devices which may
|
||||||
|
also impact connectivity.</P>
|
||||||
|
|
||||||
|
<PRE><CODE class "computeroutput">
|
||||||
|
sudo firewall-cmd --permanent --add-port=9200/tcp && sudo firewall-cmd --reload
|
||||||
|
</CODE></PRE>
|
||||||
|
|
||||||
|
<P>NOTE: The above Linux firewall command assumes the <CODE class="computeroutput">firewalld</CODE>
|
||||||
|
package has been installed on the system.</P>
|
||||||
|
|
||||||
|
</DIV>
|
||||||
</DIV>
|
</DIV>
|
||||||
</DIV>
|
</DIV>
|
||||||
|
|
||||||
|
@ -672,8 +737,7 @@ curl -k -u elastic:XXXXXX -X POST "https://localhost:9200/_security/user/ghidrau
|
||||||
<DIV class="titlepage">
|
<DIV class="titlepage">
|
||||||
<DIV>
|
<DIV>
|
||||||
<DIV>
|
<DIV>
|
||||||
<H2 class="title" style="clear: both"><A name="CreateDatabase"></A>Creating a
|
<H2 class="title" style="clear: both"><A name="CreateDatabase"></A>Creating a Database</H2>
|
||||||
Database</H2>
|
|
||||||
</DIV>
|
</DIV>
|
||||||
</DIV>
|
</DIV>
|
||||||
</DIV>
|
</DIV>
|
||||||
|
|
|
@ -53,9 +53,23 @@
|
||||||
<BR>
|
<BR>
|
||||||
|
|
||||||
|
|
||||||
<P>The dialog displays a table showing all the currently defined BSim databases/servers. Each
|
<P>The dialog displays a table showing all the currently defined BSim databases/servers.
|
||||||
entry shows a name for the BSim database, its type (postgres, elastic, or file), a host ip
|
Table columns displayed include:</P>
|
||||||
and port (if applicable), and finally the number of active connections.</P>
|
|
||||||
|
<UL>
|
||||||
|
<LI><B>Name</B> - Indicates the name of the BSim database. In the cases of an H2 <I>file</I>
|
||||||
|
database this represents the name of the file (hovering on this will show the full absolute path).</LI>
|
||||||
|
<LI><B>Type</B> - The type of database (<I>postgres</I>, <I>elastic</I> or <I>file</I>).</LI>
|
||||||
|
<LI><B>Host</B> - The network host name or IP address for a <I>postgres</I> or
|
||||||
|
<I>elastic</I> database.</LI>
|
||||||
|
<LI><B>Port</B> - The TCP port for a <I>postgres</I> or <I>elastic</I> database.</LI>
|
||||||
|
<LI><B>User</B> - The non-default user name to be used when connecting to a <I>postgres</I> or
|
||||||
|
<I>elastic</I> database. When actively connected to a <I>postgres</I> database
|
||||||
|
the actual name used for authentication will be shown.</LI>
|
||||||
|
<LI><B>Active/Idle Connections</B> - The active/idle database connections for the
|
||||||
|
connection pool associated with a <I>postgres</I> or <I>file</I> database.
|
||||||
|
This field will be blank for these databases when in a disconnected state.</LI>
|
||||||
|
</UL>
|
||||||
|
|
||||||
<P>There are four primary actions for this dialog:</P>
|
<P>There are four primary actions for this dialog:</P>
|
||||||
<A name="Manage_Servers_Actions"></A>
|
<A name="Manage_Servers_Actions"></A>
|
||||||
|
@ -68,8 +82,8 @@
|
||||||
selected entry will be deleted. This action will force an immediate disconnect for an
|
selected entry will be deleted. This action will force an immediate disconnect for an
|
||||||
active/idle connection and should be used with care.</LI>
|
active/idle connection and should be used with care.</LI>
|
||||||
|
|
||||||
<LI><IMG alt="" src="icon.bsim.disconnected"><IMG alt="" src="icon.bsim.connected">
|
<LI><IMG alt="" src="icon.bsim.disconnected"><IMG alt="" src="icon.bsim.connected"> Connect
|
||||||
Connect or disconnect an inactive database/server connection. This action is not supported
|
or disconnect an inactive database/server connection which has been selected. This action is not supported
|
||||||
by Elastic database servers.</LI>
|
by Elastic database servers.</LI>
|
||||||
|
|
||||||
<LI><IMG alt="" src="icon.bsim.change.password"> Change password - A change password
|
<LI><IMG alt="" src="icon.bsim.change.password"> Change password - A change password
|
||||||
|
@ -91,9 +105,11 @@
|
||||||
|
|
||||||
|
|
||||||
<P>Choose the type of BSim database first as that will affect the type of information that
|
<P>Choose the type of BSim database first as that will affect the type of information that
|
||||||
needs to be specified. For postgres and elastic, you need to enter host and port. For file,
|
needs to be specified. For <I>postgres</I> and <I>elastic</I>, you must enter a database name,
|
||||||
you see a button for using a filechooser to pick the file that is the local BSim H2
|
hostname/address, and port. Specify a host name of "localhost" for a server running on the local system.
|
||||||
database.</P>
|
Invalid or missing entries are shown in red. For a <I>file</I> database,
|
||||||
|
the "..." button is used to launch a filechooser for selecting an existing H2 database file
|
||||||
|
(*.mv.db).</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 6.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 12 KiB |
|
@ -77,10 +77,11 @@ public class BSimServerManager {
|
||||||
String dbTypeName = properties.getString("DBType", null);
|
String dbTypeName = properties.getString("DBType", null);
|
||||||
DBType dbType = DBType.valueOf(dbTypeName);
|
DBType dbType = DBType.valueOf(dbTypeName);
|
||||||
String name = properties.getString("Name", null);
|
String name = properties.getString("Name", null);
|
||||||
|
String user = properties.getString("User", null);
|
||||||
String host = properties.getString("Host", null);
|
String host = properties.getString("Host", null);
|
||||||
int port = properties.getInt("Port", 0);
|
int port = properties.getInt("Port", 0);
|
||||||
if (dbType != null && name != null) {
|
if (dbType != null && name != null) {
|
||||||
BSimServerInfo info = new BSimServerInfo(dbType, host, port, name);
|
BSimServerInfo info = new BSimServerInfo(dbType, user, host, port, name);
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
Msg.showError(this, null, "Error reading Bsim Server File",
|
Msg.showError(this, null, "Error reading Bsim Server File",
|
||||||
|
@ -97,6 +98,10 @@ public class BSimServerManager {
|
||||||
GProperties properties = new GProperties("BSimServerInfo");
|
GProperties properties = new GProperties("BSimServerInfo");
|
||||||
properties.putString("DBType", info.getDBType().name());
|
properties.putString("DBType", info.getDBType().name());
|
||||||
properties.putString("Name", info.getDBName());
|
properties.putString("Name", info.getDBName());
|
||||||
|
if (!info.hasDefaultLogin()) {
|
||||||
|
// save specified username - but not password
|
||||||
|
properties.putString("User", info.getUserName());
|
||||||
|
}
|
||||||
properties.putString("Host", info.getServerName());
|
properties.putString("Host", info.getServerName());
|
||||||
properties.putInt("Port", info.getPort());
|
properties.putInt("Port", info.getPort());
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ import generic.theme.GIcon;
|
||||||
import ghidra.features.bsim.gui.BSimServerManager;
|
import ghidra.features.bsim.gui.BSimServerManager;
|
||||||
import ghidra.features.bsim.query.*;
|
import ghidra.features.bsim.query.*;
|
||||||
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
||||||
import ghidra.features.bsim.query.FunctionDatabase.Error;
|
import ghidra.features.bsim.query.FunctionDatabase.BSimError;
|
||||||
import ghidra.features.bsim.query.FunctionDatabase.ErrorCategory;
|
import ghidra.features.bsim.query.FunctionDatabase.ErrorCategory;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
|
@ -175,7 +175,7 @@ public class BSimServerDialog extends DialogComponentProvider {
|
||||||
try (FunctionDatabase db = BSimClientFactory.buildClient(serverInfo, true)) {
|
try (FunctionDatabase db = BSimClientFactory.buildClient(serverInfo, true)) {
|
||||||
if (!db.initialize()) {
|
if (!db.initialize()) {
|
||||||
// TODO: Need standardized error handler
|
// TODO: Need standardized error handler
|
||||||
Error lastError = db.getLastError();
|
BSimError lastError = db.getLastError();
|
||||||
if (lastError.category != ErrorCategory.AuthenticationCancelled) {
|
if (lastError.category != ErrorCategory.AuthenticationCancelled) {
|
||||||
Msg.showError(this, getComponent(), "BSim DB Connection Failed",
|
Msg.showError(this, getComponent(), "BSim DB Connection Failed",
|
||||||
lastError.message);
|
lastError.message);
|
||||||
|
@ -195,7 +195,7 @@ public class BSimServerDialog extends DialogComponentProvider {
|
||||||
return; // password dialog entry cancelled by user
|
return; // password dialog entry cancelled by user
|
||||||
}
|
}
|
||||||
|
|
||||||
String resp = db.changePassword(db.getUserName(), pwd);
|
String resp = db.changePassword(pwd);
|
||||||
if (resp == null) {
|
if (resp == null) {
|
||||||
Msg.showInfo(this, getComponent(), "Password Changed",
|
Msg.showInfo(this, getComponent(), "Password Changed",
|
||||||
"BSim DB password successfully changed");
|
"BSim DB password successfully changed");
|
||||||
|
|
|
@ -21,11 +21,15 @@ import java.util.*;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import docking.widgets.table.*;
|
import docking.widgets.table.*;
|
||||||
import ghidra.docking.settings.Settings;
|
import ghidra.docking.settings.Settings;
|
||||||
import ghidra.features.bsim.gui.BSimServerManager;
|
import ghidra.features.bsim.gui.BSimServerManager;
|
||||||
import ghidra.features.bsim.query.BSimServerInfo;
|
import ghidra.features.bsim.query.*;
|
||||||
|
import ghidra.features.bsim.query.BSimPostgresDBConnectionManager.BSimPostgresDataSource;
|
||||||
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
||||||
|
import ghidra.framework.client.ClientUtil;
|
||||||
import ghidra.framework.plugintool.ServiceProvider;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.framework.plugintool.ServiceProviderStub;
|
import ghidra.framework.plugintool.ServiceProviderStub;
|
||||||
import ghidra.util.table.column.AbstractGColumnRenderer;
|
import ghidra.util.table.column.AbstractGColumnRenderer;
|
||||||
|
@ -90,6 +94,7 @@ public class BSimServerTableModel extends GDynamicColumnTableModel<BSimServerInf
|
||||||
descriptor.addVisibleColumn(new TypeColumn());
|
descriptor.addVisibleColumn(new TypeColumn());
|
||||||
descriptor.addVisibleColumn(new HostColumn());
|
descriptor.addVisibleColumn(new HostColumn());
|
||||||
descriptor.addVisibleColumn(new PortColumn());
|
descriptor.addVisibleColumn(new PortColumn());
|
||||||
|
descriptor.addVisibleColumn(new UserInfoColumn());
|
||||||
descriptor.addVisibleColumn(new ConnectionStatusColumn());
|
descriptor.addVisibleColumn(new ConnectionStatusColumn());
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
@ -165,6 +170,42 @@ public class BSimServerTableModel extends GDynamicColumnTableModel<BSimServerInf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class UserInfoColumn
|
||||||
|
extends AbstractDynamicTableColumn<BSimServerInfo, String, Object> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getColumnName() {
|
||||||
|
return "User";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue(BSimServerInfo serverInfo, Settings settings, Object data,
|
||||||
|
ServiceProvider provider) throws IllegalArgumentException {
|
||||||
|
if (serverInfo.hasDefaultLogin()) {
|
||||||
|
if (serverInfo.getDBType() == DBType.postgres) {
|
||||||
|
BSimPostgresDataSource ds =
|
||||||
|
BSimPostgresDBConnectionManager.getDataSourceIfExists(serverInfo);
|
||||||
|
if (ds != null) {
|
||||||
|
return ds.getUserName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: how can we determine elastic username?
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String info = serverInfo.getUserName();
|
||||||
|
boolean hasPassword = serverInfo.hasPassword();
|
||||||
|
if (hasPassword) {
|
||||||
|
info = info + ":****"; // show w/masked password
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColumnPreferredWidth() {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class HostColumn
|
private static class HostColumn
|
||||||
extends AbstractDynamicTableColumn<BSimServerInfo, String, Object> {
|
extends AbstractDynamicTableColumn<BSimServerInfo, String, Object> {
|
||||||
|
|
||||||
|
@ -176,7 +217,6 @@ public class BSimServerTableModel extends GDynamicColumnTableModel<BSimServerInf
|
||||||
@Override
|
@Override
|
||||||
public String getValue(BSimServerInfo serverInfo, Settings settings, Object data,
|
public String getValue(BSimServerInfo serverInfo, Settings settings, Object data,
|
||||||
ServiceProvider provider) throws IllegalArgumentException {
|
ServiceProvider provider) throws IllegalArgumentException {
|
||||||
|
|
||||||
return serverInfo.getServerName();
|
return serverInfo.getServerName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,17 @@
|
||||||
package ghidra.features.bsim.gui.search.dialog;
|
package ghidra.features.bsim.gui.search.dialog;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import javax.swing.JFormattedTextField.AbstractFormatterFactory;
|
||||||
import javax.swing.event.DocumentEvent;
|
import javax.swing.event.DocumentEvent;
|
||||||
import javax.swing.event.DocumentListener;
|
import javax.swing.event.DocumentListener;
|
||||||
|
import javax.swing.text.DefaultFormatter;
|
||||||
|
import javax.swing.text.DefaultFormatterFactory;
|
||||||
|
|
||||||
import docking.DialogComponentProvider;
|
import docking.DialogComponentProvider;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
|
@ -29,8 +34,11 @@ import docking.widgets.button.BrowseButton;
|
||||||
import docking.widgets.button.GRadioButton;
|
import docking.widgets.button.GRadioButton;
|
||||||
import docking.widgets.filechooser.GhidraFileChooser;
|
import docking.widgets.filechooser.GhidraFileChooser;
|
||||||
import docking.widgets.filechooser.GhidraFileChooserMode;
|
import docking.widgets.filechooser.GhidraFileChooserMode;
|
||||||
|
import docking.widgets.textfield.GFormattedTextField;
|
||||||
|
import docking.widgets.textfield.GFormattedTextField.Status;
|
||||||
import ghidra.features.bsim.query.*;
|
import ghidra.features.bsim.query.*;
|
||||||
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
||||||
|
import ghidra.framework.client.ClientUtil;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.filechooser.GhidraFileChooserModel;
|
import ghidra.util.filechooser.GhidraFileChooserModel;
|
||||||
import ghidra.util.filechooser.GhidraFileFilter;
|
import ghidra.util.filechooser.GhidraFileFilter;
|
||||||
|
@ -45,6 +53,15 @@ public class CreateBsimServerInfoDialog extends DialogComponentProvider {
|
||||||
private static final String POSTGRES = "Postgres";
|
private static final String POSTGRES = "Postgres";
|
||||||
private static final String ELASTIC = "Elastic";
|
private static final String ELASTIC = "Elastic";
|
||||||
private static final String FILE_H2 = "File";
|
private static final String FILE_H2 = "File";
|
||||||
|
|
||||||
|
private static final AbstractFormatterFactory FORMATTER_FACTORY =
|
||||||
|
new DefaultFormatterFactory(new DefaultFormatter() {
|
||||||
|
@Override
|
||||||
|
public Object stringToValue(String text) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
private GRadioButton postgresButton;
|
private GRadioButton postgresButton;
|
||||||
private GRadioButton elasticButton;
|
private GRadioButton elasticButton;
|
||||||
private GRadioButton fileButton;
|
private GRadioButton fileButton;
|
||||||
|
@ -68,16 +85,10 @@ public class CreateBsimServerInfoDialog extends DialogComponentProvider {
|
||||||
setHelpLocation(new HelpLocation("BSimSearchPlugin", "Add_Server_Definition_Dialog"));
|
setHelpLocation(new HelpLocation("BSimSearchPlugin", "Add_Server_Definition_Dialog"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BSimServerInfo getBsimServerInfo() {
|
BSimServerInfo getBsimServerInfo() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setHelpLocation(HelpLocation helpLocation) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.setHelpLocation(helpLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void okCallback() {
|
protected void okCallback() {
|
||||||
BSimServerInfo serverInfo = activePanel.getServerInfo();
|
BSimServerInfo serverInfo = activePanel.getServerInfo();
|
||||||
|
@ -88,7 +99,7 @@ public class CreateBsimServerInfoDialog extends DialogComponentProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean acceptServer(BSimServerInfo serverInfo) {
|
private boolean acceptServer(BSimServerInfo serverInfo) {
|
||||||
// FIXME: Use task to correct dialog parenting issue caused by password prompt
|
// FIXME: Use task to correct dialog parenting issue caused by password prompt
|
||||||
String errorMessage = null;
|
String errorMessage = null;
|
||||||
try (FunctionDatabase database = BSimClientFactory.buildClient(serverInfo, true)) {
|
try (FunctionDatabase database = BSimClientFactory.buildClient(serverInfo, true)) {
|
||||||
|
@ -159,6 +170,7 @@ public class CreateBsimServerInfoDialog extends DialogComponentProvider {
|
||||||
if (postgresButton.isSelected()) {
|
if (postgresButton.isSelected()) {
|
||||||
cardLayout.show(cardPanel, POSTGRES);
|
cardLayout.show(cardPanel, POSTGRES);
|
||||||
activePanel = postgresPanel;
|
activePanel = postgresPanel;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (elasticButton.isSelected()) {
|
else if (elasticButton.isSelected()) {
|
||||||
cardLayout.show(cardPanel, ELASTIC);
|
cardLayout.show(cardPanel, ELASTIC);
|
||||||
|
@ -195,8 +207,9 @@ public class CreateBsimServerInfoDialog extends DialogComponentProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DbPanel extends ServerPanel {
|
private class DbPanel extends ServerPanel {
|
||||||
private JTextField nameField;
|
private GFormattedTextField nameField;
|
||||||
private JTextField hostField;
|
private GFormattedTextField userField;
|
||||||
|
private GFormattedTextField hostField;
|
||||||
private JTextField portField;
|
private JTextField portField;
|
||||||
private DBType type;
|
private DBType type;
|
||||||
|
|
||||||
|
@ -204,12 +217,20 @@ public class CreateBsimServerInfoDialog extends DialogComponentProvider {
|
||||||
super(new PairLayout(10, 10));
|
super(new PairLayout(10, 10));
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
|
||||||
nameField = new NotifyingTextField();
|
createDBNameField();
|
||||||
hostField = new NotifyingTextField();
|
createUserField();
|
||||||
portField =
|
createHostField();
|
||||||
new NotifyingTextField(Integer.toString(BSimServerInfo.DEFAULT_POSTGRES_PORT));
|
int defaultPort = -1;
|
||||||
|
if (type == BSimServerInfo.DBType.postgres) {
|
||||||
|
defaultPort = BSimServerInfo.DEFAULT_POSTGRES_PORT;
|
||||||
|
}
|
||||||
|
else if (type == BSimServerInfo.DBType.elastic) {
|
||||||
|
defaultPort = BSimServerInfo.DEFAULT_ELASTIC_PORT;
|
||||||
|
}
|
||||||
|
portField = new NotifyingTextField(Integer.toString(defaultPort));
|
||||||
|
|
||||||
JLabel nameLabel = new JLabel("DB Name:", SwingConstants.RIGHT);
|
JLabel nameLabel = new JLabel("DB Name:", SwingConstants.RIGHT);
|
||||||
|
JLabel userLabel = new JLabel("User (optional):", SwingConstants.RIGHT);
|
||||||
JLabel hostLabel = new JLabel("Host:", SwingConstants.RIGHT);
|
JLabel hostLabel = new JLabel("Host:", SwingConstants.RIGHT);
|
||||||
JLabel portLabel = new JLabel("Port:", SwingConstants.RIGHT);
|
JLabel portLabel = new JLabel("Port:", SwingConstants.RIGHT);
|
||||||
nameLabel.setLabelFor(nameField);
|
nameLabel.setLabelFor(nameField);
|
||||||
|
@ -218,21 +239,197 @@ public class CreateBsimServerInfoDialog extends DialogComponentProvider {
|
||||||
|
|
||||||
add(nameLabel);
|
add(nameLabel);
|
||||||
add(nameField);
|
add(nameField);
|
||||||
|
add(userLabel);
|
||||||
|
add(userField);
|
||||||
add(hostLabel);
|
add(hostLabel);
|
||||||
add(hostField);
|
add(hostField);
|
||||||
add(portLabel);
|
add(portLabel);
|
||||||
add(portField);
|
add(portField);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setStatus(String msg) {
|
||||||
|
CreateBsimServerInfoDialog.this.setStatusText(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createDBNameField() {
|
||||||
|
|
||||||
|
nameField = new GFormattedTextField(FORMATTER_FACTORY, "");
|
||||||
|
nameField.setName("Name");
|
||||||
|
nameField.setText("");
|
||||||
|
nameField.setDefaultValue("");
|
||||||
|
nameField.setIsError(true);
|
||||||
|
nameField.setEditable(true);
|
||||||
|
|
||||||
|
nameField.setInputVerifier(new InputVerifier() {
|
||||||
|
@Override
|
||||||
|
public boolean verify(JComponent input) {
|
||||||
|
setStatus("");
|
||||||
|
String dbName = nameField.getText().trim();
|
||||||
|
if (dbName.length() == 0) {
|
||||||
|
setStatus("");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Naming restrictions based upon PostgreSQL and its allowance of unicode chars
|
||||||
|
for (int i = 0; i < dbName.length(); i++) {
|
||||||
|
char c = dbName.charAt(i);
|
||||||
|
if (Character.isLetter(c)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i == 0 || (!Character.isDigit(c) && c != '_')) {
|
||||||
|
setStatus("Unsupported database name");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldYieldFocus(JComponent source, JComponent target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
nameField.addKeyListener(new KeyAdapter() {
|
||||||
|
@Override
|
||||||
|
public void keyPressed(KeyEvent e) {
|
||||||
|
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
||||||
|
e.consume();
|
||||||
|
nameField.setText("");
|
||||||
|
nameField.setDefaultValue("");
|
||||||
|
nameField.setIsError(true);
|
||||||
|
}
|
||||||
|
checkForValidDialog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
nameField.addTextEntryStatusListener(f -> checkForValidDialog());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String HOSTNAME_IP_REGEX =
|
||||||
|
"^[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*$";
|
||||||
|
private static final Pattern HOSTNAME_IP_PATTERN = Pattern.compile(HOSTNAME_IP_REGEX);
|
||||||
|
|
||||||
|
private void createHostField() {
|
||||||
|
|
||||||
|
hostField = new GFormattedTextField(FORMATTER_FACTORY, "");
|
||||||
|
hostField.setName("Host");
|
||||||
|
hostField.setText("");
|
||||||
|
hostField.setDefaultValue("");
|
||||||
|
hostField.setIsError(true);
|
||||||
|
hostField.setEditable(true);
|
||||||
|
|
||||||
|
hostField.setInputVerifier(new InputVerifier() {
|
||||||
|
@Override
|
||||||
|
public boolean verify(JComponent input) {
|
||||||
|
setStatus("");
|
||||||
|
String hostname = hostField.getText().trim();
|
||||||
|
if (hostname.length() == 0) {
|
||||||
|
setStatus("");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Matcher hostMatch = HOSTNAME_IP_PATTERN.matcher(hostname);
|
||||||
|
if (!hostMatch.matches()) {
|
||||||
|
setStatus("Unsupported host name or IP address");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldYieldFocus(JComponent source, JComponent target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
hostField.addKeyListener(new KeyAdapter() {
|
||||||
|
@Override
|
||||||
|
public void keyPressed(KeyEvent e) {
|
||||||
|
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
||||||
|
e.consume();
|
||||||
|
hostField.setText("");
|
||||||
|
hostField.setDefaultValue("");
|
||||||
|
hostField.setIsError(true);
|
||||||
|
}
|
||||||
|
checkForValidDialog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
hostField.addTextEntryStatusListener(f -> checkForValidDialog());
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Username pattern based on PostgreSQL restrictions
|
||||||
|
private static final String USERNAME_REGEX = "^[a-zA-Z_][a-zA-Z0-9_$]*$";
|
||||||
|
private static final Pattern USERNAME_PATTERN = Pattern.compile(USERNAME_REGEX);
|
||||||
|
|
||||||
|
private void createUserField() {
|
||||||
|
|
||||||
|
userField = new GFormattedTextField(FORMATTER_FACTORY, "");
|
||||||
|
userField.setName("User");
|
||||||
|
userField.setText("");
|
||||||
|
userField.setDefaultValue("");
|
||||||
|
userField.setEditable(true);
|
||||||
|
|
||||||
|
userField.setInputVerifier(new InputVerifier() {
|
||||||
|
@Override
|
||||||
|
public boolean verify(JComponent input) {
|
||||||
|
setStatus("");
|
||||||
|
String username = userField.getText().trim();
|
||||||
|
if (username.length() == 0) {
|
||||||
|
setStatus("");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Matcher userMatch = USERNAME_PATTERN.matcher(username);
|
||||||
|
if (!userMatch.matches()) {
|
||||||
|
setStatus("Unsupported database user name");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldYieldFocus(JComponent source, JComponent target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
userField.addKeyListener(new KeyAdapter() {
|
||||||
|
@Override
|
||||||
|
public void keyPressed(KeyEvent e) {
|
||||||
|
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
||||||
|
e.consume();
|
||||||
|
userField.setText("");
|
||||||
|
userField.setDefaultValue("");
|
||||||
|
userField.setIsError(false);
|
||||||
|
}
|
||||||
|
checkForValidDialog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
userField.addTextEntryStatusListener(f -> checkForValidDialog());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
BSimServerInfo getServerInfo() {
|
BSimServerInfo getServerInfo() {
|
||||||
|
if (nameField.getTextEntryStatus() == Status.INVALID ||
|
||||||
|
userField.getTextEntryStatus() == Status.INVALID ||
|
||||||
|
hostField.getTextEntryStatus() == Status.INVALID) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String user = userField.getText().trim();
|
||||||
|
if (ClientUtil.getUserName().equals(user)) {
|
||||||
|
user = null;
|
||||||
|
}
|
||||||
|
|
||||||
String name = nameField.getText().trim();
|
String name = nameField.getText().trim();
|
||||||
String host = hostField.getText().trim();
|
String host = hostField.getText().trim();
|
||||||
|
|
||||||
int port = getPort(portField.getText().trim());
|
int port = getPort(portField.getText().trim());
|
||||||
if (name.isBlank() || host.isBlank() || port < 0) {
|
if (name.isBlank() || host.isBlank() || port < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new BSimServerInfo(type, host, port, name);
|
|
||||||
|
return new BSimServerInfo(type, user, host, port, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +488,7 @@ public class CreateBsimServerInfoDialog extends DialogComponentProvider {
|
||||||
if (file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new BSimServerInfo(DBType.file, null, -1, path);
|
return new BSimServerInfo(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,24 +500,24 @@ public class CreateBsimServerInfoDialog extends DialogComponentProvider {
|
||||||
public NotifyingTextField(String initialText) {
|
public NotifyingTextField(String initialText) {
|
||||||
super(20);
|
super(20);
|
||||||
setText(initialText);
|
setText(initialText);
|
||||||
getDocument().addDocumentListener(new DocumentListener() {
|
getDocument().addDocumentListener(new MyFieldListener());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
class MyFieldListener implements DocumentListener {
|
||||||
public void insertUpdate(DocumentEvent e) {
|
@Override
|
||||||
checkForValidDialog();
|
public void insertUpdate(DocumentEvent e) {
|
||||||
}
|
checkForValidDialog();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeUpdate(DocumentEvent e) {
|
public void removeUpdate(DocumentEvent e) {
|
||||||
checkForValidDialog();
|
checkForValidDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void changedUpdate(DocumentEvent e) {
|
public void changedUpdate(DocumentEvent e) {
|
||||||
checkForValidDialog();
|
checkForValidDialog();
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ import javax.security.auth.callback.NameCallback;
|
||||||
import javax.security.auth.callback.PasswordCallback;
|
import javax.security.auth.callback.PasswordCallback;
|
||||||
|
|
||||||
import org.apache.commons.dbcp2.BasicDataSource;
|
import org.apache.commons.dbcp2.BasicDataSource;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
||||||
import ghidra.features.bsim.query.FunctionDatabase.ConnectionType;
|
import ghidra.features.bsim.query.FunctionDatabase.ConnectionType;
|
||||||
|
@ -283,10 +282,12 @@ public class BSimPostgresDBConnectionManager {
|
||||||
*/
|
*/
|
||||||
private Connection connect() throws SQLException, CancelledException {
|
private Connection connect() throws SQLException, CancelledException {
|
||||||
|
|
||||||
String userName = bds.getUsername();
|
String loginError = null;
|
||||||
bds.setUsername(StringUtils.isBlank(userName) ? ClientUtil.getUserName() : userName);
|
|
||||||
bds.setPassword(null);
|
serverInfo.setUserInfo(bds);
|
||||||
connectionType = ConnectionType.SSL_No_Authentication;
|
|
||||||
|
connectionType = serverInfo.hasPassword() ? ConnectionType.SSL_Password_Authentication
|
||||||
|
: ConnectionType.SSL_No_Authentication;
|
||||||
try {
|
try {
|
||||||
// Specify SSL connection properties
|
// Specify SSL connection properties
|
||||||
setSSLProperties();
|
setSSLProperties();
|
||||||
|
@ -299,6 +300,10 @@ public class BSimPostgresDBConnectionManager {
|
||||||
if (e.getMessage().contains("password-based authentication") ||
|
if (e.getMessage().contains("password-based authentication") ||
|
||||||
e.getMessage().contains("SCRAM-based") ||
|
e.getMessage().contains("SCRAM-based") ||
|
||||||
e.getMessage().contains("password authentication failed")) {
|
e.getMessage().contains("password authentication failed")) {
|
||||||
|
if (serverInfo.hasPassword()) {
|
||||||
|
loginError = "Access denied: " + serverInfo;
|
||||||
|
Msg.error(this, loginError);
|
||||||
|
}
|
||||||
// Use Ghidra's authentication infrastructure
|
// Use Ghidra's authentication infrastructure
|
||||||
connectionType = ConnectionType.SSL_Password_Authentication; // Try again with a password
|
connectionType = ConnectionType.SSL_Password_Authentication; // Try again with a password
|
||||||
// fallthru to second attempt at getConnection
|
// fallthru to second attempt at getConnection
|
||||||
|
@ -319,7 +324,6 @@ public class BSimPostgresDBConnectionManager {
|
||||||
" idle=" + bds.getNumIdle());
|
" idle=" + bds.getNumIdle());
|
||||||
}
|
}
|
||||||
|
|
||||||
String loginError = null;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ClientAuthenticator clientAuthenticator = null;
|
ClientAuthenticator clientAuthenticator = null;
|
||||||
if (connectionType == ConnectionType.SSL_Password_Authentication) {
|
if (connectionType == ConnectionType.SSL_Password_Authentication) {
|
||||||
|
@ -327,9 +331,11 @@ public class BSimPostgresDBConnectionManager {
|
||||||
if (clientAuthenticator == null) { // Make sure authenticator is registered
|
if (clientAuthenticator == null) { // Make sure authenticator is registered
|
||||||
throw new SQLException("No registered authenticator");
|
throw new SQLException("No registered authenticator");
|
||||||
}
|
}
|
||||||
NameCallback nameCb = new NameCallback("User ID:");
|
NameCallback nameCb = new NameCallback("User ID:", bds.getUsername());
|
||||||
nameCb.setName(bds.getUsername());
|
if (!serverInfo.hasDefaultLogin()) {
|
||||||
PasswordCallback passCb = new PasswordCallback("Password:", false);
|
nameCb.setName(bds.getUsername());
|
||||||
|
}
|
||||||
|
PasswordCallback passCb = new PasswordCallback(" ", false); // force use of default prompting
|
||||||
try {
|
try {
|
||||||
if (!clientAuthenticator.processPasswordCallbacks(
|
if (!clientAuthenticator.processPasswordCallbacks(
|
||||||
"BSim Database Authentication", "BSim Database Server",
|
"BSim Database Authentication", "BSim Database Server",
|
||||||
|
@ -338,9 +344,8 @@ public class BSimPostgresDBConnectionManager {
|
||||||
}
|
}
|
||||||
bds.setPassword(new String(passCb.getPassword()));
|
bds.setPassword(new String(passCb.getPassword()));
|
||||||
// User may have specified new username, or this may return NULL
|
// User may have specified new username, or this may return NULL
|
||||||
userName = nameCb.getName();
|
if (serverInfo.hasDefaultLogin()) {
|
||||||
if (!StringUtils.isBlank(userName)) {
|
bds.setUsername(nameCb.getName());
|
||||||
bds.setUsername(userName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -16,12 +16,15 @@
|
||||||
package ghidra.features.bsim.query;
|
package ghidra.features.bsim.query;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.net.MalformedURLException;
|
import java.net.*;
|
||||||
import java.net.URL;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.apache.commons.dbcp2.BasicDataSource;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import ghidra.framework.client.ClientUtil;
|
||||||
|
|
||||||
public class BSimServerInfo implements Comparable<BSimServerInfo> {
|
public class BSimServerInfo implements Comparable<BSimServerInfo> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,6 +51,7 @@ public class BSimServerInfo implements Comparable<BSimServerInfo> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private final DBType dbType;
|
private final DBType dbType;
|
||||||
|
private final String userinfo; // username[:password]
|
||||||
private final String host;
|
private final String host;
|
||||||
private final int port;
|
private final int port;
|
||||||
private final String dbName;
|
private final String dbName;
|
||||||
|
@ -56,6 +60,62 @@ public class BSimServerInfo implements Comparable<BSimServerInfo> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new {@link BSimServerInfo} object
|
* Construct a new {@link BSimServerInfo} object
|
||||||
|
*
|
||||||
|
* @param dbType BSim DB type
|
||||||
|
* @param userinfo connection user info, {@code username[:password]} (ignored for {@link DBType#file}).
|
||||||
|
* If blank, {@link ClientUtil#getUserName()} is used.
|
||||||
|
* @param host host name (ignored for {@link DBType#file})
|
||||||
|
* @param port port number (ignored for {@link DBType#file})
|
||||||
|
* @param dbName name of database (simple database name except for {@link DBType#file}
|
||||||
|
* which should reflect an absolute file path. On Windows OS the path may start with a
|
||||||
|
* drive letter.
|
||||||
|
* @throws IllegalArgumentException if invalid arguments are specified
|
||||||
|
*/
|
||||||
|
public BSimServerInfo(DBType dbType, String userinfo, String host, int port, String dbName) {
|
||||||
|
Objects.requireNonNull(dbType, "DBType must be specified");
|
||||||
|
this.dbType = dbType;
|
||||||
|
|
||||||
|
if ((dbType == DBType.postgres || dbType == DBType.elastic) && StringUtils.isEmpty(host)) {
|
||||||
|
throw new IllegalArgumentException("host required");
|
||||||
|
}
|
||||||
|
|
||||||
|
dbName = dbName.trim();
|
||||||
|
if (StringUtils.isEmpty(dbName)) {
|
||||||
|
throw new IllegalArgumentException("Non-empty dbName required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbType == DBType.file) {
|
||||||
|
host = null;
|
||||||
|
port = -1;
|
||||||
|
userinfo = null;
|
||||||
|
dbName = cleanupFilename(dbName);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (dbName.contains("/") || dbName.contains("\\")) { // may want additional validation
|
||||||
|
throw new IllegalArgumentException("Invalid " + dbType + " dbName: " + dbName);
|
||||||
|
}
|
||||||
|
userinfo = cleanupUserInfo(userinfo);
|
||||||
|
if (port <= 0) {
|
||||||
|
port = -1;
|
||||||
|
}
|
||||||
|
if (dbType == DBType.postgres && port <= 0) {
|
||||||
|
port = DEFAULT_POSTGRES_PORT;
|
||||||
|
}
|
||||||
|
if (dbType == DBType.elastic && port <= 0) {
|
||||||
|
port = DEFAULT_ELASTIC_PORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.userinfo = userinfo;
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
this.dbName = dbName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new {@link BSimServerInfo} object. For non-file database the user's defaut
|
||||||
|
* username is used (see {@link ClientUtil#getUserName()}).
|
||||||
|
*
|
||||||
* @param dbType BSim DB type
|
* @param dbType BSim DB type
|
||||||
* @param host host name (ignored for {@link DBType#file})
|
* @param host host name (ignored for {@link DBType#file})
|
||||||
* @param port port number (ignored for {@link DBType#file})
|
* @param port port number (ignored for {@link DBType#file})
|
||||||
|
@ -65,49 +125,34 @@ public class BSimServerInfo implements Comparable<BSimServerInfo> {
|
||||||
* @throws IllegalArgumentException if invalid arguments are specified
|
* @throws IllegalArgumentException if invalid arguments are specified
|
||||||
*/
|
*/
|
||||||
public BSimServerInfo(DBType dbType, String host, int port, String dbName) {
|
public BSimServerInfo(DBType dbType, String host, int port, String dbName) {
|
||||||
Objects.requireNonNull(dbType, "DBType must be specified");
|
this(dbType, null, host, port, dbName);
|
||||||
this.dbType = dbType;
|
}
|
||||||
|
|
||||||
if ((dbType == DBType.postgres || dbType == DBType.elastic) && StringUtils.isEmpty(host)) {
|
|
||||||
throw new IllegalArgumentException("host required");
|
|
||||||
}
|
|
||||||
this.host = host;
|
|
||||||
|
|
||||||
if (port <= 0) {
|
|
||||||
port = -1;
|
|
||||||
}
|
|
||||||
if (dbType == DBType.postgres && port <= 0) {
|
|
||||||
port = DEFAULT_POSTGRES_PORT;
|
|
||||||
}
|
|
||||||
if (dbType == DBType.elastic && port <= 0) {
|
|
||||||
port = DEFAULT_ELASTIC_PORT;
|
|
||||||
}
|
|
||||||
this.port = port;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new {@link BSimServerInfo} object for a {@link DBType#file} type database.
|
||||||
|
*
|
||||||
|
* @param dbName name of database which should reflect an absolute file path.
|
||||||
|
* On Windows OS the path may start with a drive letter.
|
||||||
|
* @throws IllegalArgumentException if invalid arguments are specified
|
||||||
|
*/
|
||||||
|
public BSimServerInfo(String dbName) {
|
||||||
|
dbType = DBType.file;
|
||||||
|
userinfo = null;
|
||||||
|
host = null;
|
||||||
|
port = -1;
|
||||||
dbName = dbName.trim();
|
dbName = dbName.trim();
|
||||||
if (StringUtils.isEmpty(dbName)) {
|
if (StringUtils.isEmpty(dbName)) {
|
||||||
throw new IllegalArgumentException("Non-empty dbName required");
|
throw new IllegalArgumentException("Non-empty dbName required");
|
||||||
}
|
}
|
||||||
if (dbType == DBType.file) {
|
this.dbName = cleanupFilename(dbName);
|
||||||
// transform dbName into acceptable H2 DB file path
|
|
||||||
dbName = dbName.replace("\\", "/");
|
|
||||||
if ((!dbName.startsWith("/") && !isWindowsFilePath(dbName)) || dbName.endsWith("/")) {
|
|
||||||
throw new IllegalArgumentException("Invalid absolute file path: " + dbName);
|
|
||||||
}
|
|
||||||
if (!dbName.endsWith(H2_FILE_EXTENSION)) {
|
|
||||||
dbName += H2_FILE_EXTENSION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (dbName.contains("/") || dbName.contains("\\")) { // may want additional validation
|
|
||||||
throw new IllegalArgumentException("Invalid " + dbType + " dbName: " + dbName);
|
|
||||||
}
|
|
||||||
this.dbName = dbName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new {@link BSimServerInfo} object from a suitable database URL
|
* Construct a new {@link BSimServerInfo} object from a suitable database URL
|
||||||
* (i.e., {@code postgresql:}, {@code https:}, {@code elastic:}, {@code file:}).
|
* (i.e., {@code postgresql:}, {@code https:}, {@code elastic:}, {@code file:}).
|
||||||
* @param url supported BSim database URL
|
*
|
||||||
|
* @param url supported BSim database URL. For non-file URLs, the hostname or
|
||||||
|
* address may be preceeded by a DB username (e.g., postgresql://user@host:port/dbname
|
||||||
* @throws IllegalArgumentException if unsupported URL protocol specified
|
* @throws IllegalArgumentException if unsupported URL protocol specified
|
||||||
*/
|
*/
|
||||||
public BSimServerInfo(URL url) throws IllegalArgumentException {
|
public BSimServerInfo(URL url) throws IllegalArgumentException {
|
||||||
|
@ -118,18 +163,21 @@ public class BSimServerInfo implements Comparable<BSimServerInfo> {
|
||||||
if (protocol.equals("postgresql")) {
|
if (protocol.equals("postgresql")) {
|
||||||
t = DBType.postgres;
|
t = DBType.postgres;
|
||||||
host = checkURLField(url.getHost(), "host");
|
host = checkURLField(url.getHost(), "host");
|
||||||
|
userinfo = getURLUserInfo(url);
|
||||||
int p = url.getPort();
|
int p = url.getPort();
|
||||||
port = p <= 0 ? DEFAULT_POSTGRES_PORT : p;
|
port = p <= 0 ? DEFAULT_POSTGRES_PORT : p;
|
||||||
}
|
}
|
||||||
else if (protocol.equals("https") || protocol.equals("elastic")) {
|
else if (protocol.equals("https") || protocol.equals("elastic")) {
|
||||||
t = DBType.elastic;
|
t = DBType.elastic;
|
||||||
host = checkURLField(url.getHost(), "host");
|
host = checkURLField(url.getHost(), "host");
|
||||||
|
userinfo = getURLUserInfo(url);
|
||||||
int p = url.getPort();
|
int p = url.getPort();
|
||||||
port = p <= 0 ? DEFAULT_ELASTIC_PORT : p;
|
port = p <= 0 ? DEFAULT_ELASTIC_PORT : p;
|
||||||
}
|
}
|
||||||
else if (protocol.startsWith("file")) {
|
else if (protocol.startsWith("file")) {
|
||||||
t = DBType.file;
|
t = DBType.file;
|
||||||
host = null;
|
host = null;
|
||||||
|
userinfo = null;
|
||||||
port = -1;
|
port = -1;
|
||||||
if (!"".equals(url.getHost())) {
|
if (!"".equals(url.getHost())) {
|
||||||
throw new IllegalArgumentException("Remote file URL not supported: " + url);
|
throw new IllegalArgumentException("Remote file URL not supported: " + url);
|
||||||
|
@ -146,7 +194,7 @@ public class BSimServerInfo implements Comparable<BSimServerInfo> {
|
||||||
}
|
}
|
||||||
path = path.substring(1).strip();
|
path = path.substring(1).strip();
|
||||||
}
|
}
|
||||||
path = checkURLField(path, "path");
|
path = urlDecode(checkURLField(path, "path"));
|
||||||
if (dbType == DBType.file) {
|
if (dbType == DBType.file) {
|
||||||
if (path.endsWith("/")) {
|
if (path.endsWith("/")) {
|
||||||
throw new IllegalArgumentException("Missing DB filepath in URL: " + url);
|
throw new IllegalArgumentException("Missing DB filepath in URL: " + url);
|
||||||
|
@ -162,6 +210,53 @@ public class BSimServerInfo implements Comparable<BSimServerInfo> {
|
||||||
dbName = path;
|
dbName = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getURLUserInfo(URL url) {
|
||||||
|
|
||||||
|
String userinfo = url.getUserInfo();
|
||||||
|
if (userinfo == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pwSep = userinfo.indexOf(':');
|
||||||
|
String urlUserInfo;
|
||||||
|
if (pwSep >= 0) {
|
||||||
|
urlUserInfo = urlDecode(userinfo.substring(0, pwSep)) + ":" +
|
||||||
|
urlDecode(userinfo.substring(pwSep + 1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
urlUserInfo = urlDecode(userinfo);
|
||||||
|
}
|
||||||
|
return cleanupUserInfo(urlUserInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String cleanupUserInfo(String userinfo) {
|
||||||
|
if (StringUtils.isBlank(userinfo)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
userinfo = userinfo.trim();
|
||||||
|
int pwdSep = userinfo.indexOf(':');
|
||||||
|
if (pwdSep == 0) {
|
||||||
|
throw new IllegalArgumentException("Invalid userinfo specified");
|
||||||
|
}
|
||||||
|
else if (pwdSep > 0 && (userinfo.length() - pwdSep) == 0) {
|
||||||
|
throw new IllegalArgumentException("Invalid userinfo specified");
|
||||||
|
}
|
||||||
|
return userinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String cleanupFilename(String name) {
|
||||||
|
// transform dbName into acceptable H2 DB file path
|
||||||
|
String dbName = name.trim();
|
||||||
|
dbName = dbName.replace("\\", "/");
|
||||||
|
if ((!dbName.startsWith("/") && !isWindowsFilePath(dbName)) || dbName.endsWith("/")) {
|
||||||
|
throw new IllegalArgumentException("Invalid absolute file path: " + dbName);
|
||||||
|
}
|
||||||
|
if (!dbName.endsWith(H2_FILE_EXTENSION)) {
|
||||||
|
dbName += H2_FILE_EXTENSION;
|
||||||
|
}
|
||||||
|
return dbName;
|
||||||
|
}
|
||||||
|
|
||||||
private static String checkURLField(String val, String name) {
|
private static String checkURLField(String val, String name) {
|
||||||
if (StringUtils.isEmpty(val)) {
|
if (StringUtils.isEmpty(val)) {
|
||||||
throw new IllegalArgumentException("Invalid " + name + " in URL");
|
throw new IllegalArgumentException("Invalid " + name + " in URL");
|
||||||
|
@ -199,29 +294,57 @@ public class BSimServerInfo implements Comparable<BSimServerInfo> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return BSim server info in URL format
|
* Return BSim server info in URL format.
|
||||||
|
* Warning: If userinfo with password has been specified it will be returned in the URL.
|
||||||
* @return BSim server info in URL format
|
* @return BSim server info in URL format
|
||||||
*/
|
*/
|
||||||
public String toURLString() {
|
public String toURLString() {
|
||||||
switch (dbType) {
|
switch (dbType) {
|
||||||
case postgres:
|
case postgres:
|
||||||
return "postgresql://" + host + getPortString() + "/" + dbName;
|
return "postgresql://" + formatURLUserInfo() + host + getPortString() + "/" +
|
||||||
|
urlEncode(dbName);
|
||||||
|
|
||||||
case elastic:
|
case elastic:
|
||||||
return "https://" + host + getPortString() + "/" + dbName;
|
return "https://" + formatURLUserInfo() + host + getPortString() + "/" +
|
||||||
|
urlEncode(dbName);
|
||||||
|
|
||||||
case file: // h2:
|
case file: // h2:
|
||||||
return "file:" + dbName;
|
return "file:" + urlEncode(dbName);
|
||||||
}
|
}
|
||||||
throw new RuntimeException("Unsupported DBType: " + dbType);
|
throw new RuntimeException("Unsupported DBType: " + dbType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String urlEncode(String text) {
|
||||||
|
return URLEncoder.encode(text, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String urlDecode(String text) {
|
||||||
|
return URLDecoder.decode(text, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatURLUserInfo() {
|
||||||
|
if (userinfo == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int pwSep = userinfo.indexOf(':');
|
||||||
|
String urlUserInfo;
|
||||||
|
if (pwSep >= 0) {
|
||||||
|
urlUserInfo = urlEncode(userinfo.substring(0, pwSep)) + ":" +
|
||||||
|
urlEncode(userinfo.substring(pwSep + 1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
urlUserInfo = urlEncode(userinfo);
|
||||||
|
}
|
||||||
|
return urlUserInfo + "@";
|
||||||
|
}
|
||||||
|
|
||||||
private String getPortString() {
|
private String getPortString() {
|
||||||
return port > 0 ? (":" + Integer.toString(port)) : "";
|
return port > 0 ? (":" + Integer.toString(port)) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return BSim server info in URL
|
* Return BSim server info in URL.
|
||||||
|
* Warning: If userinfo with password has been specified it will be returned in the URL.
|
||||||
* @return BSim server info in URL
|
* @return BSim server info in URL
|
||||||
* @throws MalformedURLException if unable to form supported URL
|
* @throws MalformedURLException if unable to form supported URL
|
||||||
*/
|
*/
|
||||||
|
@ -236,6 +359,58 @@ public class BSimServerInfo implements Comparable<BSimServerInfo> {
|
||||||
return dbType;
|
return dbType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUserInfo(BasicDataSource bds) {
|
||||||
|
bds.setUsername(getUserName());
|
||||||
|
if (hasPassword()) {
|
||||||
|
bds.setPassword(userinfo.substring(userinfo.indexOf(':') + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if user information includes password.
|
||||||
|
* NOTE: Use of passwords with this object and URLs is discouraged.
|
||||||
|
* @return true if user information includes password which
|
||||||
|
*/
|
||||||
|
public boolean hasPassword() {
|
||||||
|
return userinfo != null && userinfo.contains(":");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine of user info was stipulated during construction
|
||||||
|
* @return true if user info was stipulated during construction
|
||||||
|
*/
|
||||||
|
public boolean hasDefaultLogin() {
|
||||||
|
return userinfo == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the remote database user name to be used when establishing a connection.
|
||||||
|
* User name obtained from the user information which was provided during instantiation.
|
||||||
|
* @return remote database user information (null for {@link DBType#file}).
|
||||||
|
*/
|
||||||
|
public String getUserName() {
|
||||||
|
if (dbType == DBType.file) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (userinfo == null) {
|
||||||
|
return ClientUtil.getUserName();
|
||||||
|
}
|
||||||
|
String username = userinfo;
|
||||||
|
int pwdSep = userinfo.indexOf(':');
|
||||||
|
if (pwdSep > 0) {
|
||||||
|
username = userinfo.substring(0, pwdSep);
|
||||||
|
}
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the remote database user information to be used when establishing a connection.
|
||||||
|
* @return remote database user information (null for {@link DBType#file}).
|
||||||
|
*/
|
||||||
|
public String getUserInfo() {
|
||||||
|
return userinfo;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the server hostname or IP address as originally specified.
|
* Get the server hostname or IP address as originally specified.
|
||||||
* @return hostname or IP address as originally specified
|
* @return hostname or IP address as originally specified
|
||||||
|
@ -282,7 +457,14 @@ public class BSimServerInfo implements Comparable<BSimServerInfo> {
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
// use dbType.ordinal; enum hashcodes vary from run to run
|
// use dbType.ordinal; enum hashcodes vary from run to run
|
||||||
return Objects.hash(dbName, dbType.ordinal(), host, port);
|
int hashcode = Objects.hash(dbName, dbType.ordinal(), host, port);
|
||||||
|
// Due to the use of hashcode by BSimServerManager for persisting server entries
|
||||||
|
// we cannot change the hashing function above and must only incorporate inclusion
|
||||||
|
// of userinfo if it is specified.
|
||||||
|
if (userinfo != null) {
|
||||||
|
hashcode = 31 * hashcode + userinfo.hashCode();
|
||||||
|
}
|
||||||
|
return hashcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -293,7 +475,8 @@ public class BSimServerInfo implements Comparable<BSimServerInfo> {
|
||||||
return false;
|
return false;
|
||||||
if (obj instanceof BSimServerInfo other) {
|
if (obj instanceof BSimServerInfo other) {
|
||||||
return Objects.equals(dbName, other.dbName) && dbType == other.dbType &&
|
return Objects.equals(dbName, other.dbName) && dbType == other.dbType &&
|
||||||
Objects.equals(host, other.host) && port == other.port;
|
Objects.equals(userinfo, other.userinfo) && Objects.equals(host, other.host) &&
|
||||||
|
port == other.port;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,7 @@ import ghidra.features.bsim.query.facade.SFOverviewInfo;
|
||||||
import ghidra.features.bsim.query.facade.SFQueryInfo;
|
import ghidra.features.bsim.query.facade.SFQueryInfo;
|
||||||
import ghidra.features.bsim.query.protocol.*;
|
import ghidra.features.bsim.query.protocol.*;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.program.model.data.DataUtilities;
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.StringUtilities;
|
|
||||||
|
|
||||||
public interface FunctionDatabase extends AutoCloseable {
|
public interface FunctionDatabase extends AutoCloseable {
|
||||||
|
|
||||||
|
@ -85,11 +83,11 @@ public interface FunctionDatabase extends AutoCloseable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Error { // Error structure returned by getLastError
|
public static class BSimError { // Error structure returned by getLastError
|
||||||
public ErrorCategory category;
|
public ErrorCategory category;
|
||||||
public String message;
|
public String message;
|
||||||
|
|
||||||
public Error(ErrorCategory cat, String msg) {
|
public BSimError(ErrorCategory cat, String msg) {
|
||||||
category = cat;
|
category = cat;
|
||||||
message = msg;
|
message = msg;
|
||||||
}
|
}
|
||||||
|
@ -120,12 +118,11 @@ public interface FunctionDatabase extends AutoCloseable {
|
||||||
/**
|
/**
|
||||||
* Issue password change request to the server.
|
* Issue password change request to the server.
|
||||||
* The method {@link #isPasswordChangeAllowed()} must be invoked first to ensure that
|
* The method {@link #isPasswordChangeAllowed()} must be invoked first to ensure that
|
||||||
* the user password may be changed.
|
* the user password may be changed.
|
||||||
* @param username to change
|
|
||||||
* @param newPassword is password data
|
* @param newPassword is password data
|
||||||
* @return null if change was successful, or the error message
|
* @return null if change was successful, or the error message
|
||||||
*/
|
*/
|
||||||
public default String changePassword(String username, char[] newPassword) {
|
public default String changePassword(char[] newPassword) {
|
||||||
if (getStatus() != Status.Ready) {
|
if (getStatus() != Status.Ready) {
|
||||||
return "Connection not established";
|
return "Connection not established";
|
||||||
}
|
}
|
||||||
|
@ -134,7 +131,7 @@ public interface FunctionDatabase extends AutoCloseable {
|
||||||
}
|
}
|
||||||
PasswordChange passwordChange = new PasswordChange();
|
PasswordChange passwordChange = new PasswordChange();
|
||||||
try {
|
try {
|
||||||
passwordChange.username = username;
|
passwordChange.username = getUserName();
|
||||||
passwordChange.newPassword = newPassword;
|
passwordChange.newPassword = newPassword;
|
||||||
ResponsePassword response = passwordChange.execute(this);
|
ResponsePassword response = passwordChange.execute(this);
|
||||||
if (!response.changeSuccessful) {
|
if (!response.changeSuccessful) {
|
||||||
|
@ -162,14 +159,6 @@ public interface FunctionDatabase extends AutoCloseable {
|
||||||
*/
|
*/
|
||||||
public String getUserName();
|
public String getUserName();
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a specific user name for connection. Must be called before connection is initialized.
|
|
||||||
* If this method is not called, connection will use user name of process
|
|
||||||
*
|
|
||||||
* @param userName the user name
|
|
||||||
*/
|
|
||||||
public void setUserName(String userName);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return factory the database is using to create LSHVector objects
|
* @return factory the database is using to create LSHVector objects
|
||||||
*/
|
*/
|
||||||
|
@ -218,7 +207,7 @@ public interface FunctionDatabase extends AutoCloseable {
|
||||||
* If the last query failed to produce a response, use this method to recover the error message
|
* If the last query failed to produce a response, use this method to recover the error message
|
||||||
* @return a String describing the error
|
* @return a String describing the error
|
||||||
*/
|
*/
|
||||||
public Error getLastError();
|
public BSimError getLastError();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a query to the database. The response is returned as a QueryResponseRecord.
|
* Send a query to the database. The response is returned as a QueryResponseRecord.
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -92,7 +92,7 @@ public abstract class AbstractSQLFunctionDatabase<VF extends LSHVectorFactory>
|
||||||
|
|
||||||
protected final VF vectorFactory; // Factory used to generate LSHVector objects
|
protected final VF vectorFactory; // Factory used to generate LSHVector objects
|
||||||
|
|
||||||
private Error lasterror;
|
private BSimError lasterror;
|
||||||
private Status status;
|
private Status status;
|
||||||
private boolean isinit;
|
private boolean isinit;
|
||||||
|
|
||||||
|
@ -1120,11 +1120,6 @@ public abstract class AbstractSQLFunctionDatabase<VF extends LSHVectorFactory>
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUserName(String userName) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LSHVectorFactory getLSHVectorFactory() {
|
public LSHVectorFactory getLSHVectorFactory() {
|
||||||
return vectorFactory;
|
return vectorFactory;
|
||||||
|
@ -1155,7 +1150,7 @@ public abstract class AbstractSQLFunctionDatabase<VF extends LSHVectorFactory>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Error getLastError() {
|
public BSimError getLastError() {
|
||||||
return lasterror;
|
return lasterror;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1188,7 +1183,7 @@ public abstract class AbstractSQLFunctionDatabase<VF extends LSHVectorFactory>
|
||||||
}
|
}
|
||||||
catch (CancelledSQLException e) {
|
catch (CancelledSQLException e) {
|
||||||
status = Status.Error;
|
status = Status.Error;
|
||||||
lasterror = new Error(ErrorCategory.AuthenticationCancelled,
|
lasterror = new BSimError(ErrorCategory.AuthenticationCancelled,
|
||||||
"Authentication cancelled by user");
|
"Authentication cancelled by user");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1201,19 +1196,19 @@ public abstract class AbstractSQLFunctionDatabase<VF extends LSHVectorFactory>
|
||||||
}
|
}
|
||||||
String msg = cause.getMessage();
|
String msg = cause.getMessage();
|
||||||
if (msg.contains("already in use:")) {
|
if (msg.contains("already in use:")) {
|
||||||
lasterror = new Error(ErrorCategory.Initialization,
|
lasterror = new BSimError(ErrorCategory.Initialization,
|
||||||
"Database already in use by another process");
|
"Database already in use by another process");
|
||||||
}
|
}
|
||||||
else if (msg.contains("authentication failed") ||
|
else if (msg.contains("authentication failed") ||
|
||||||
msg.contains("requires a valid client certificate")) {
|
msg.contains("requires a valid client certificate")) {
|
||||||
lasterror =
|
lasterror =
|
||||||
new Error(ErrorCategory.Authentication, "Could not authenticate with database");
|
new BSimError(ErrorCategory.Authentication, "Could not authenticate with database");
|
||||||
}
|
}
|
||||||
else if (msg.contains("does not exist") && !msg.contains(" role ")) {
|
else if (msg.contains("does not exist") && !msg.contains(" role ")) {
|
||||||
lasterror = new Error(ErrorCategory.Nodatabase, cause.getMessage());
|
lasterror = new BSimError(ErrorCategory.Nodatabase, cause.getMessage());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lasterror = new Error(ErrorCategory.Initialization,
|
lasterror = new BSimError(ErrorCategory.Initialization,
|
||||||
"Database error on initialization: " + cause.getMessage());
|
"Database error on initialization: " + cause.getMessage());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1628,29 +1623,29 @@ public abstract class AbstractSQLFunctionDatabase<VF extends LSHVectorFactory>
|
||||||
lasterror = null;
|
lasterror = null;
|
||||||
try {
|
try {
|
||||||
if (!(query instanceof CreateDatabase) && !initialize()) {
|
if (!(query instanceof CreateDatabase) && !initialize()) {
|
||||||
lasterror = new Error(ErrorCategory.Nodatabase, "The database does not exist");
|
lasterror = new BSimError(ErrorCategory.Nodatabase, "The database does not exist");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
query.buildResponseTemplate();
|
query.buildResponseTemplate();
|
||||||
QueryResponseRecord response = doQuery(query, db);
|
QueryResponseRecord response = doQuery(query, db);
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
lasterror = new Error(ErrorCategory.Fatal, "Unknown query type");
|
lasterror = new BSimError(ErrorCategory.Fatal, "Unknown query type");
|
||||||
query.clearResponse();
|
query.clearResponse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (DatabaseNonFatalException err) {
|
catch (DatabaseNonFatalException err) {
|
||||||
lasterror = new Error(ErrorCategory.Nonfatal,
|
lasterror = new BSimError(ErrorCategory.Nonfatal,
|
||||||
"Skipping -" + query.getName() + "- : " + err.getMessage());
|
"Skipping -" + query.getName() + "- : " + err.getMessage());
|
||||||
query.clearResponse();
|
query.clearResponse();
|
||||||
}
|
}
|
||||||
catch (LSHException err) {
|
catch (LSHException err) {
|
||||||
lasterror = new Error(ErrorCategory.Fatal,
|
lasterror = new BSimError(ErrorCategory.Fatal,
|
||||||
"Fatal error during -" + query.getName() + "- : " + err.getMessage());
|
"Fatal error during -" + query.getName() + "- : " + err.getMessage());
|
||||||
query.clearResponse();
|
query.clearResponse();
|
||||||
}
|
}
|
||||||
catch (SQLException err) {
|
catch (SQLException err) {
|
||||||
lasterror = new Error(ErrorCategory.Fatal,
|
lasterror = new BSimError(ErrorCategory.Fatal,
|
||||||
"SQL error during -" + query.getName() + "- : " + err.getMessage());
|
"SQL error during -" + query.getName() + "- : " + err.getMessage());
|
||||||
query.clearResponse();
|
query.clearResponse();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -34,7 +34,7 @@ public class FunctionDatabaseProxy implements FunctionDatabase {
|
||||||
private DatabaseInformation info;
|
private DatabaseInformation info;
|
||||||
private LSHVectorFactory vectorFactory;
|
private LSHVectorFactory vectorFactory;
|
||||||
private URL httpURL;
|
private URL httpURL;
|
||||||
private Error lasterror;
|
private BSimError lasterror;
|
||||||
private Status status;
|
private Status status;
|
||||||
private boolean isinit;
|
private boolean isinit;
|
||||||
private XmlErrorHandler xmlErrorHandler;
|
private XmlErrorHandler xmlErrorHandler;
|
||||||
|
@ -83,11 +83,6 @@ public class FunctionDatabaseProxy implements FunctionDatabase {
|
||||||
return ClientUtil.getUserName();
|
return ClientUtil.getUserName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUserName(String userName) {
|
|
||||||
// Not currently implemented
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LSHVectorFactory getLSHVectorFactory() {
|
public LSHVectorFactory getLSHVectorFactory() {
|
||||||
return vectorFactory;
|
return vectorFactory;
|
||||||
|
@ -123,7 +118,8 @@ public class FunctionDatabaseProxy implements FunctionDatabase {
|
||||||
}
|
}
|
||||||
if (httpURL == null) {
|
if (httpURL == null) {
|
||||||
status = Status.Error;
|
status = Status.Error;
|
||||||
lasterror = new FunctionDatabase.Error(ErrorCategory.Initialization, "MalformedURL");
|
lasterror =
|
||||||
|
new FunctionDatabase.BSimError(ErrorCategory.Initialization, "MalformedURL");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QueryInfo queryInfo = new QueryInfo();
|
QueryInfo queryInfo = new QueryInfo();
|
||||||
|
@ -145,7 +141,7 @@ public class FunctionDatabaseProxy implements FunctionDatabase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Error getLastError() {
|
public BSimError getLastError() {
|
||||||
return lasterror;
|
return lasterror;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +164,8 @@ public class FunctionDatabaseProxy implements FunctionDatabase {
|
||||||
ResponseError respError = new ResponseError();
|
ResponseError respError = new ResponseError();
|
||||||
respError.restoreXml(parser, vectorFactory);
|
respError.restoreXml(parser, vectorFactory);
|
||||||
parser.dispose();
|
parser.dispose();
|
||||||
lasterror = new FunctionDatabase.Error(ErrorCategory.Fatal, respError.errorMessage);
|
lasterror =
|
||||||
|
new FunctionDatabase.BSimError(ErrorCategory.Fatal, respError.errorMessage);
|
||||||
query.clearResponse();
|
query.clearResponse();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -184,7 +181,7 @@ public class FunctionDatabaseProxy implements FunctionDatabase {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
lasterror = new FunctionDatabase.Error(ErrorCategory.Connection, ex.getMessage());
|
lasterror = new FunctionDatabase.BSimError(ErrorCategory.Connection, ex.getMessage());
|
||||||
status = Status.Error;
|
status = Status.Error;
|
||||||
query.clearResponse();
|
query.clearResponse();
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -190,8 +190,9 @@ public final class PostgresFunctionDatabase
|
||||||
@Override
|
@Override
|
||||||
protected void generateRawDatabase() throws SQLException {
|
protected void generateRawDatabase() throws SQLException {
|
||||||
BSimServerInfo serverInfo = postgresDs.getServerInfo();
|
BSimServerInfo serverInfo = postgresDs.getServerInfo();
|
||||||
BSimServerInfo defaultServerInfo = new BSimServerInfo(DBType.postgres,
|
BSimServerInfo defaultServerInfo =
|
||||||
serverInfo.getServerName(), serverInfo.getPort(), DEFAULT_DATABASE_NAME);
|
new BSimServerInfo(DBType.postgres, serverInfo.getUserInfo(),
|
||||||
|
serverInfo.getServerName(), serverInfo.getPort(), DEFAULT_DATABASE_NAME);
|
||||||
String createdbstring = "CREATE DATABASE \"" + serverInfo.getDBName() + '"';
|
String createdbstring = "CREATE DATABASE \"" + serverInfo.getDBName() + '"';
|
||||||
BSimPostgresDataSource defaultDs =
|
BSimPostgresDataSource defaultDs =
|
||||||
BSimPostgresDBConnectionManager.getDataSource(defaultServerInfo);
|
BSimPostgresDBConnectionManager.getDataSource(defaultServerInfo);
|
||||||
|
@ -502,14 +503,6 @@ public final class PostgresFunctionDatabase
|
||||||
return postgresDs.getUserName();
|
return postgresDs.getUserName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUserName(String userName) {
|
|
||||||
if (postgresDs.getStatus() == Status.Ready) {
|
|
||||||
throw new IllegalStateException("Connection has already been established");
|
|
||||||
}
|
|
||||||
postgresDs.setPreferredUserName(userName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryResponseRecord doQuery(BSimQuery<?> query, Connection c)
|
public QueryResponseRecord doQuery(BSimQuery<?> query, Connection c)
|
||||||
throws SQLException, LSHException, DatabaseNonFatalException {
|
throws SQLException, LSHException, DatabaseNonFatalException {
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -31,8 +31,6 @@ public class ElasticConnection {
|
||||||
|
|
||||||
protected String hostURL; // http://hostname:port
|
protected String hostURL; // http://hostname:port
|
||||||
protected String httpURLbase; // Main URL to elasticsearch
|
protected String httpURLbase; // Main URL to elasticsearch
|
||||||
private HttpURLConnection connection = null;
|
|
||||||
private Writer writer;
|
|
||||||
private int lastResponseCode;
|
private int lastResponseCode;
|
||||||
|
|
||||||
public ElasticConnection(String url, String repo) {
|
public ElasticConnection(String url, String repo) {
|
||||||
|
@ -41,61 +39,13 @@ public class ElasticConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
if (connection != null) {
|
// nothing to do - http connections do not persist
|
||||||
connection.disconnect();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean lastRequestSuccessful() {
|
public boolean lastRequestSuccessful() {
|
||||||
return (lastResponseCode >= 200) && (lastResponseCode < 300);
|
return (lastResponseCode >= 200) && (lastResponseCode < 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a new request to the elastic server. This establishes the OutputStream for writing the body of the request
|
|
||||||
* @param command is the type of command
|
|
||||||
* @param path is the overarching index/type/<command> path
|
|
||||||
* @throws IOException for problems with the socket
|
|
||||||
*/
|
|
||||||
public void startHttpRequest(String command, String path) throws IOException {
|
|
||||||
URL httpURL = new URL(httpURLbase + path);
|
|
||||||
connection = (HttpURLConnection) httpURL.openConnection();
|
|
||||||
connection.setRequestMethod(command);
|
|
||||||
connection.setRequestProperty("Content-Type", "application/json");
|
|
||||||
connection.setDoOutput(true);
|
|
||||||
writer = new OutputStreamWriter(connection.getOutputStream());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startHttpBulkRequest(String bulkCommand) throws IOException {
|
|
||||||
URL httpURL = new URL(hostURL + bulkCommand);
|
|
||||||
connection = (HttpURLConnection) httpURL.openConnection();
|
|
||||||
connection.setRequestMethod(POST);
|
|
||||||
connection.setRequestProperty("Content-Type", "application/x-ndjson");
|
|
||||||
connection.setDoOutput(true);
|
|
||||||
writer = new OutputStreamWriter(connection.getOutputStream());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startHttpRawRequest(String command, String path) throws IOException {
|
|
||||||
URL httpURL = new URL(hostURL + path);
|
|
||||||
connection = (HttpURLConnection) httpURL.openConnection();
|
|
||||||
connection.setRequestMethod(command);
|
|
||||||
connection.setRequestProperty("Content-Type", "application/json");
|
|
||||||
connection.setDoOutput(true);
|
|
||||||
writer = new OutputStreamWriter(connection.getOutputStream());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a request with no input body, URI only
|
|
||||||
* @param command is the command to issue
|
|
||||||
* @param path is the overarching request path: index/...
|
|
||||||
* @throws IOException for problems with the socket
|
|
||||||
*/
|
|
||||||
public void startHttpURICommand(String command, String path) throws IOException {
|
|
||||||
URL httpURL = new URL(httpURLbase + path);
|
|
||||||
connection = (HttpURLConnection) httpURL.openConnection();
|
|
||||||
connection.setRequestMethod(command);
|
|
||||||
connection.setDoOutput(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assuming the writer has been closed and connection.getResponseCode() is called
|
* Assuming the writer has been closed and connection.getResponseCode() is called
|
||||||
* placing the value in lastResponseCode, read the response and parse into a JSONObject
|
* placing the value in lastResponseCode, read the response and parse into a JSONObject
|
||||||
|
@ -103,15 +53,21 @@ public class ElasticConnection {
|
||||||
* @throws IOException for problems with the socket
|
* @throws IOException for problems with the socket
|
||||||
* @throws ParseException for JSON parse errors
|
* @throws ParseException for JSON parse errors
|
||||||
*/
|
*/
|
||||||
private JSONObject grabResponse() throws IOException, ParseException {
|
private JSONObject grabResponse(HttpURLConnection connection)
|
||||||
|
throws IOException, ParseException {
|
||||||
JSONParser parser = new JSONParser();
|
JSONParser parser = new JSONParser();
|
||||||
Reader reader;
|
InputStream in;
|
||||||
if (lastRequestSuccessful()) {
|
if (lastRequestSuccessful()) {
|
||||||
reader = new InputStreamReader(connection.getInputStream());
|
in = connection.getInputStream();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
reader = new InputStreamReader(connection.getErrorStream());
|
in = connection.getErrorStream();
|
||||||
}
|
}
|
||||||
|
if (in == null) {
|
||||||
|
// Connection error occurred
|
||||||
|
throw new IOException(connection.getResponseMessage());
|
||||||
|
}
|
||||||
|
Reader reader = new InputStreamReader(in);
|
||||||
JSONObject jsonObject = (JSONObject) parser.parse(reader);
|
JSONObject jsonObject = (JSONObject) parser.parse(reader);
|
||||||
return jsonObject;
|
return jsonObject;
|
||||||
}
|
}
|
||||||
|
@ -156,12 +112,18 @@ public class ElasticConnection {
|
||||||
*/
|
*/
|
||||||
public JSONObject executeRawStatement(String command, String path, String body)
|
public JSONObject executeRawStatement(String command, String path, String body)
|
||||||
throws ElasticException {
|
throws ElasticException {
|
||||||
|
HttpURLConnection connection = null;
|
||||||
try {
|
try {
|
||||||
startHttpRawRequest(command, path);
|
URL httpURL = new URL(hostURL + path);
|
||||||
writer.write(body);
|
connection = (HttpURLConnection) httpURL.openConnection();
|
||||||
writer.close();
|
connection.setRequestMethod(command);
|
||||||
|
connection.setRequestProperty("Content-Type", "application/json");
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
try (Writer writer = new OutputStreamWriter(connection.getOutputStream())) {
|
||||||
|
writer.write(body);
|
||||||
|
}
|
||||||
lastResponseCode = connection.getResponseCode();
|
lastResponseCode = connection.getResponseCode();
|
||||||
JSONObject resp = grabResponse();
|
JSONObject resp = grabResponse(connection);
|
||||||
if (!lastRequestSuccessful()) {
|
if (!lastRequestSuccessful()) {
|
||||||
throw new ElasticException(parseErrorJSON(resp));
|
throw new ElasticException(parseErrorJSON(resp));
|
||||||
}
|
}
|
||||||
|
@ -173,6 +135,11 @@ public class ElasticConnection {
|
||||||
catch (ParseException e) {
|
catch (ParseException e) {
|
||||||
throw new ElasticException("Error parsing response: " + e.getMessage());
|
throw new ElasticException("Error parsing response: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,12 +152,18 @@ public class ElasticConnection {
|
||||||
*/
|
*/
|
||||||
public void executeStatementNoResponse(String command, String path, String body)
|
public void executeStatementNoResponse(String command, String path, String body)
|
||||||
throws ElasticException {
|
throws ElasticException {
|
||||||
|
HttpURLConnection connection = null;
|
||||||
try {
|
try {
|
||||||
startHttpRequest(command, path);
|
URL httpURL = new URL(httpURLbase + path);
|
||||||
writer.write(body);
|
connection = (HttpURLConnection) httpURL.openConnection();
|
||||||
writer.close();
|
connection.setRequestMethod(command);
|
||||||
|
connection.setRequestProperty("Content-Type", "application/json");
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
try (Writer writer = new OutputStreamWriter(connection.getOutputStream())) {
|
||||||
|
writer.write(body);
|
||||||
|
}
|
||||||
lastResponseCode = connection.getResponseCode();
|
lastResponseCode = connection.getResponseCode();
|
||||||
JSONObject resp = grabResponse();
|
JSONObject resp = grabResponse(connection);
|
||||||
if (!lastRequestSuccessful()) {
|
if (!lastRequestSuccessful()) {
|
||||||
throw new ElasticException(parseErrorJSON(resp));
|
throw new ElasticException(parseErrorJSON(resp));
|
||||||
}
|
}
|
||||||
|
@ -201,6 +174,11 @@ public class ElasticConnection {
|
||||||
catch (ParseException e) {
|
catch (ParseException e) {
|
||||||
throw new ElasticException("Error parsing response: " + e.getMessage());
|
throw new ElasticException("Error parsing response: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -213,12 +191,18 @@ public class ElasticConnection {
|
||||||
*/
|
*/
|
||||||
public JSONObject executeStatement(String command, String path, String body)
|
public JSONObject executeStatement(String command, String path, String body)
|
||||||
throws ElasticException {
|
throws ElasticException {
|
||||||
|
HttpURLConnection connection = null;
|
||||||
try {
|
try {
|
||||||
startHttpRequest(command, path);
|
URL httpURL = new URL(httpURLbase + path);
|
||||||
writer.write(body);
|
connection = (HttpURLConnection) httpURL.openConnection();
|
||||||
writer.close();
|
connection.setRequestMethod(command);
|
||||||
|
connection.setRequestProperty("Content-Type", "application/json");
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
try (Writer writer = new OutputStreamWriter(connection.getOutputStream())) {
|
||||||
|
writer.write(body);
|
||||||
|
}
|
||||||
lastResponseCode = connection.getResponseCode();
|
lastResponseCode = connection.getResponseCode();
|
||||||
JSONObject resp = grabResponse();
|
JSONObject resp = grabResponse(connection);
|
||||||
if (!lastRequestSuccessful()) {
|
if (!lastRequestSuccessful()) {
|
||||||
throw new ElasticException(parseErrorJSON(resp));
|
throw new ElasticException(parseErrorJSON(resp));
|
||||||
}
|
}
|
||||||
|
@ -230,6 +214,11 @@ public class ElasticConnection {
|
||||||
catch (ParseException e) {
|
catch (ParseException e) {
|
||||||
throw new ElasticException("Error parsing response: " + e.getMessage());
|
throw new ElasticException("Error parsing response: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -243,12 +232,18 @@ public class ElasticConnection {
|
||||||
*/
|
*/
|
||||||
public JSONObject executeStatementExpectFailure(String command, String path, String body)
|
public JSONObject executeStatementExpectFailure(String command, String path, String body)
|
||||||
throws ElasticException {
|
throws ElasticException {
|
||||||
|
HttpURLConnection connection = null;
|
||||||
try {
|
try {
|
||||||
startHttpRequest(command, path);
|
URL httpURL = new URL(httpURLbase + path);
|
||||||
writer.write(body);
|
connection = (HttpURLConnection) httpURL.openConnection();
|
||||||
writer.close();
|
connection.setRequestMethod(command);
|
||||||
|
connection.setRequestProperty("Content-Type", "application/json");
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
try (Writer writer = new OutputStreamWriter(connection.getOutputStream())) {
|
||||||
|
writer.write(body);
|
||||||
|
}
|
||||||
lastResponseCode = connection.getResponseCode();
|
lastResponseCode = connection.getResponseCode();
|
||||||
JSONObject resp = grabResponse();
|
JSONObject resp = grabResponse(connection);
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
|
@ -257,6 +252,11 @@ public class ElasticConnection {
|
||||||
catch (ParseException e) {
|
catch (ParseException e) {
|
||||||
throw new ElasticException("Error parsing response: " + e.getMessage());
|
throw new ElasticException("Error parsing response: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -268,12 +268,18 @@ public class ElasticConnection {
|
||||||
* @throws ElasticException for any problems with the connection
|
* @throws ElasticException for any problems with the connection
|
||||||
*/
|
*/
|
||||||
public JSONObject executeBulk(String path, String body) throws ElasticException {
|
public JSONObject executeBulk(String path, String body) throws ElasticException {
|
||||||
|
HttpURLConnection connection = null;
|
||||||
try {
|
try {
|
||||||
startHttpBulkRequest(path);
|
URL httpURL = new URL(hostURL + path);
|
||||||
writer.write(body);
|
connection = (HttpURLConnection) httpURL.openConnection();
|
||||||
writer.close();
|
connection.setRequestMethod(POST);
|
||||||
|
connection.setRequestProperty("Content-Type", "application/x-ndjson");
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
try (Writer writer = new OutputStreamWriter(connection.getOutputStream())) {
|
||||||
|
writer.write(body);
|
||||||
|
}
|
||||||
lastResponseCode = connection.getResponseCode();
|
lastResponseCode = connection.getResponseCode();
|
||||||
JSONObject resp = grabResponse();
|
JSONObject resp = grabResponse(connection);
|
||||||
if (!lastRequestSuccessful()) {
|
if (!lastRequestSuccessful()) {
|
||||||
throw new ElasticException(parseErrorJSON(resp));
|
throw new ElasticException(parseErrorJSON(resp));
|
||||||
}
|
}
|
||||||
|
@ -285,13 +291,22 @@ public class ElasticConnection {
|
||||||
catch (ParseException e) {
|
catch (ParseException e) {
|
||||||
throw new ElasticException("Error parsing response: " + e.getMessage());
|
throw new ElasticException("Error parsing response: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject executeURIOnly(String command, String path) throws ElasticException {
|
public JSONObject executeURIOnly(String command, String path) throws ElasticException {
|
||||||
|
HttpURLConnection connection = null;
|
||||||
try {
|
try {
|
||||||
startHttpURICommand(command, path);
|
URL httpURL = new URL(httpURLbase + path);
|
||||||
|
connection = (HttpURLConnection) httpURL.openConnection();
|
||||||
|
connection.setRequestMethod(command);
|
||||||
|
connection.setDoOutput(true);
|
||||||
lastResponseCode = connection.getResponseCode();
|
lastResponseCode = connection.getResponseCode();
|
||||||
JSONObject resp = grabResponse();
|
JSONObject resp = grabResponse(connection);
|
||||||
if (!lastRequestSuccessful()) {
|
if (!lastRequestSuccessful()) {
|
||||||
throw new ElasticException(parseErrorJSON(resp));
|
throw new ElasticException(parseErrorJSON(resp));
|
||||||
}
|
}
|
||||||
|
@ -303,5 +318,10 @@ public class ElasticConnection {
|
||||||
catch (ParseException e) {
|
catch (ParseException e) {
|
||||||
throw new ElasticException("Error parsing response: " + e.getMessage());
|
throw new ElasticException("Error parsing response: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -60,14 +60,13 @@ public class ElasticDatabase implements FunctionDatabase {
|
||||||
public static final int MAX_VECTOR_BULK = 200; // Maximum vectors ingested in one bulk request
|
public static final int MAX_VECTOR_BULK = 200; // Maximum vectors ingested in one bulk request
|
||||||
|
|
||||||
private ElasticConnection connection; // Low-level connection to the database
|
private ElasticConnection connection; // Low-level connection to the database
|
||||||
private String userName = null; // User name for server authentication
|
|
||||||
private ConnectionType connectionType = ConnectionType.Unencrypted_No_Authentication;
|
private ConnectionType connectionType = ConnectionType.Unencrypted_No_Authentication;
|
||||||
private DatabaseInformation info; // Information about the active database
|
private DatabaseInformation info; // Information about the active database
|
||||||
private Base64VectorFactory vectorFactory; // factory used to create BSim feature vectors
|
private Base64VectorFactory vectorFactory; // factory used to create BSim feature vectors
|
||||||
private final BSimServerInfo serverInfo; // NOTE: does not reflect the use of http vs https
|
private final BSimServerInfo serverInfo; // NOTE: does not reflect the use of http vs https
|
||||||
private final String baseURL; // Base URL for connecting to elasticsearch, i.e. http://hostname:9200
|
private final String baseURL; // Base URL for connecting to elasticsearch, i.e. http://hostname:9200
|
||||||
private final String repository; // Name of the repository, prefix to all elasticsearch indices
|
private final String repository; // Name of the repository, prefix to all elasticsearch indices
|
||||||
private Error lastError; // Info on error caused by last action taken on this interface (null if no error)
|
private BSimError lastError; // Info on error caused by last action taken on this interface (null if no error)
|
||||||
private Status status; // status of the connection
|
private Status status; // status of the connection
|
||||||
private boolean initialized; // true if the connection has been successfully initialized
|
private boolean initialized; // true if the connection has been successfully initialized
|
||||||
|
|
||||||
|
@ -2022,8 +2021,8 @@ public class ElasticDatabase implements FunctionDatabase {
|
||||||
throw new MalformedURLException("URL path must indicate the repository only");
|
throw new MalformedURLException("URL path must indicate the repository only");
|
||||||
}
|
}
|
||||||
repository = path.substring(1);
|
repository = path.substring(1);
|
||||||
this.serverInfo =
|
this.serverInfo = new BSimServerInfo(DBType.elastic, null, baseURL.getHost(),
|
||||||
new BSimServerInfo(DBType.elastic, baseURL.getHost(), baseURL.getPort(), repository);
|
baseURL.getPort(), repository);
|
||||||
this.baseURL = fullURL.substring(0, fullURL.length() - path.length());
|
this.baseURL = fullURL.substring(0, fullURL.length() - path.length());
|
||||||
|
|
||||||
lastError = null;
|
lastError = null;
|
||||||
|
@ -2398,15 +2397,7 @@ public class ElasticDatabase implements FunctionDatabase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUserName() {
|
public String getUserName() {
|
||||||
if (userName != null) {
|
return serverInfo.getUserName();
|
||||||
return userName;
|
|
||||||
}
|
|
||||||
return ClientUtil.getUserName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUserName(String userName) {
|
|
||||||
this.userName = userName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2450,14 +2441,14 @@ public class ElasticDatabase implements FunctionDatabase {
|
||||||
vectorFactory.set(config.weightfactory, config.idflookup, config.info.settings);
|
vectorFactory.set(config.weightfactory, config.idflookup, config.info.settings);
|
||||||
}
|
}
|
||||||
catch (ElasticException err) {
|
catch (ElasticException err) {
|
||||||
lastError = new Error(ErrorCategory.Initialization,
|
lastError = new BSimError(ErrorCategory.Initialization,
|
||||||
"Database error on initialization: " + err.getMessage());
|
"Database error on initialization: " + err.getMessage());
|
||||||
status = Status.Error;
|
status = Status.Error;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch (NoDatabaseException err) {
|
catch (NoDatabaseException err) {
|
||||||
info = null;
|
info = null;
|
||||||
lastError = new Error(ErrorCategory.Nodatabase,
|
lastError = new BSimError(ErrorCategory.Nodatabase,
|
||||||
"Database has not been created yet: " + err.getMessage());
|
"Database has not been created yet: " + err.getMessage());
|
||||||
initialized = true;
|
initialized = true;
|
||||||
status = Status.Ready;
|
status = Status.Ready;
|
||||||
|
@ -2480,14 +2471,14 @@ public class ElasticDatabase implements FunctionDatabase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Error getLastError() {
|
public BSimError getLastError() {
|
||||||
return lastError;
|
return lastError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryResponseRecord query(BSimQuery<?> query) {
|
public QueryResponseRecord query(BSimQuery<?> query) {
|
||||||
if ((!isInitialized()) && (!(query instanceof CreateDatabase))) {
|
if ((!isInitialized()) && (!(query instanceof CreateDatabase))) {
|
||||||
lastError = new Error(ErrorCategory.Nodatabase, "The database does not exist");
|
lastError = new BSimError(ErrorCategory.Nodatabase, "The database does not exist");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
lastError = null;
|
lastError = null;
|
||||||
|
@ -2554,22 +2545,22 @@ public class ElasticDatabase implements FunctionDatabase {
|
||||||
fdbPasswordChange((PasswordChange) query);
|
fdbPasswordChange((PasswordChange) query);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lastError = new Error(ErrorCategory.Fatal, "Unknown query type");
|
lastError = new BSimError(ErrorCategory.Fatal, "Unknown query type");
|
||||||
query.clearResponse();
|
query.clearResponse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (DatabaseNonFatalException err) {
|
catch (DatabaseNonFatalException err) {
|
||||||
lastError = new Error(ErrorCategory.Nonfatal,
|
lastError = new BSimError(ErrorCategory.Nonfatal,
|
||||||
"Skipping -" + query.getName() + "- : " + err.getMessage());
|
"Skipping -" + query.getName() + "- : " + err.getMessage());
|
||||||
query.clearResponse();
|
query.clearResponse();
|
||||||
}
|
}
|
||||||
catch (LSHException err) {
|
catch (LSHException err) {
|
||||||
lastError = new Error(ErrorCategory.Fatal,
|
lastError = new BSimError(ErrorCategory.Fatal,
|
||||||
"Fatal error during -" + query.getName() + "- : " + err.getMessage());
|
"Fatal error during -" + query.getName() + "- : " + err.getMessage());
|
||||||
query.clearResponse();
|
query.clearResponse();
|
||||||
}
|
}
|
||||||
catch (ElasticException err) {
|
catch (ElasticException err) {
|
||||||
lastError = new Error(ErrorCategory.Fatal,
|
lastError = new BSimError(ErrorCategory.Fatal,
|
||||||
"Elastic error during -" + query.getName() + "- : " + err.getMessage());
|
"Elastic error during -" + query.getName() + "- : " + err.getMessage());
|
||||||
query.clearResponse();
|
query.clearResponse();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -384,7 +384,7 @@ public class SimilarFunctionQueryService implements AutoCloseable {
|
||||||
return database.getLSHVectorFactory();
|
return database.getLSHVectorFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
public FunctionDatabase.Error getLastError() {
|
public FunctionDatabase.BSimError getLastError() {
|
||||||
if (database == null) {
|
if (database == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -17,7 +17,8 @@ package ghidra.features.bsim.query.ingest;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.*;
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -32,10 +33,8 @@ import ghidra.features.bsim.query.protocol.QueryName;
|
||||||
import ghidra.framework.*;
|
import ghidra.framework.*;
|
||||||
import ghidra.framework.client.ClientUtil;
|
import ghidra.framework.client.ClientUtil;
|
||||||
import ghidra.framework.client.HeadlessClientAuthenticator;
|
import ghidra.framework.client.HeadlessClientAuthenticator;
|
||||||
import ghidra.framework.data.DomainObjectAdapter;
|
|
||||||
import ghidra.framework.protocol.ghidra.GhidraURL;
|
import ghidra.framework.protocol.ghidra.GhidraURL;
|
||||||
import ghidra.net.SSLContextInitializer;
|
import ghidra.net.SSLContextInitializer;
|
||||||
import ghidra.program.database.ProgramDB;
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.SystemUtilities;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -335,10 +334,6 @@ public class BSimLaunchable implements GhidraLaunchable {
|
||||||
optionValueMap.put(option, params[i]);
|
optionValueMap.put(option, params[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String connectingUserName = optionValueMap.get(USER_OPTION);
|
|
||||||
if (connectingUserName == null) {
|
|
||||||
connectingUserName = optionValueMap.put(USER_OPTION, ClientUtil.getUserName());
|
|
||||||
}
|
|
||||||
return subParams;
|
return subParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -981,9 +976,9 @@ public class BSimLaunchable implements GhidraLaunchable {
|
||||||
" <config_template> - large_32 | medium_32 | medium_64 | medium_cpool | medium_nosize \n" +
|
" <config_template> - large_32 | medium_32 | medium_64 | medium_cpool | medium_nosize \n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"BSim URL Forms (bsimURL):\n" +
|
"BSim URL Forms (bsimURL):\n" +
|
||||||
" postgresql://<hostname>[:<port>]/<dbname>\n" +
|
" postgresql://[username@]<hostname>[:<port>]/<dbname>\n" +
|
||||||
" elastic://<hostname>[:<port>]/<dbname>\n" +
|
" elastic://[username@]<hostname>[:<port>]/<dbname>\n" +
|
||||||
" https://<hostname>[:<port>]/<dbname>\n" +
|
" https://[username@]<hostname>[:<port>]/<dbname>\n" +
|
||||||
" file:/[<local-dirpath>/]<dbname>\n" +
|
" file:/[<local-dirpath>/]<dbname>\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"Ghidra URL Forms (ghidraURL):\n" +
|
"Ghidra URL Forms (ghidraURL):\n" +
|
||||||
|
@ -1010,7 +1005,13 @@ public class BSimLaunchable implements GhidraLaunchable {
|
||||||
run(params);
|
run(params);
|
||||||
}
|
}
|
||||||
catch (MalformedURLException e) {
|
catch (MalformedURLException e) {
|
||||||
Msg.error(this, "Invalid URL specified: " + e.getMessage());
|
String msg = e.getMessage();
|
||||||
|
if (msg == null) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Msg.error(this, "Invalid URL specified: " + msg);
|
||||||
|
}
|
||||||
System.exit(22); // EINVAL
|
System.exit(22); // EINVAL
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
|
@ -1019,7 +1020,13 @@ public class BSimLaunchable implements GhidraLaunchable {
|
||||||
System.exit(22); // EINVAL
|
System.exit(22); // EINVAL
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
Msg.error(this, e.getMessage());
|
String msg = e.getMessage();
|
||||||
|
if (msg == null) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Msg.error(this, msg);
|
||||||
|
}
|
||||||
System.exit(1); // Misc Error
|
System.exit(1); // Misc Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1059,7 +1066,7 @@ public class BSimLaunchable implements GhidraLaunchable {
|
||||||
|
|
||||||
// Use BSim log config to ensure we get desired console output
|
// Use BSim log config to ensure we get desired console output
|
||||||
System.setProperty(LoggingInitialization.LOG4J2_CONFIGURATION_PROPERTY,
|
System.setProperty(LoggingInitialization.LOG4J2_CONFIGURATION_PROPERTY,
|
||||||
BSIM_LOGGING_CONFIGURATION_FILE);
|
BSIM_LOGGING_CONFIGURATION_FILE);
|
||||||
|
|
||||||
ApplicationConfiguration config;
|
ApplicationConfiguration config;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -1084,6 +1091,10 @@ public class BSimLaunchable implements GhidraLaunchable {
|
||||||
ghidra.framework.protocol.ghidra.Handler.registerHandler();
|
ghidra.framework.protocol.ghidra.Handler.registerHandler();
|
||||||
ghidra.features.bsim.query.postgresql.Handler.registerHandler();
|
ghidra.features.bsim.query.postgresql.Handler.registerHandler();
|
||||||
|
|
||||||
|
if (connectingUserName == null) {
|
||||||
|
// Force default login name
|
||||||
|
connectingUserName = ClientUtil.getUserName();
|
||||||
|
}
|
||||||
HeadlessClientAuthenticator.installHeadlessClientAuthenticator(connectingUserName, certPath,
|
HeadlessClientAuthenticator.installHeadlessClientAuthenticator(connectingUserName, certPath,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -16,7 +16,6 @@
|
||||||
package ghidra.features.bsim.query.ingest;
|
package ghidra.features.bsim.query.ingest;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -29,9 +28,8 @@ import org.xml.sax.SAXException;
|
||||||
import generic.lsh.vector.LSHVectorFactory;
|
import generic.lsh.vector.LSHVectorFactory;
|
||||||
import ghidra.app.decompiler.DecompileException;
|
import ghidra.app.decompiler.DecompileException;
|
||||||
import ghidra.features.bsim.query.*;
|
import ghidra.features.bsim.query.*;
|
||||||
import ghidra.features.bsim.query.FunctionDatabase.Error;
|
import ghidra.features.bsim.query.FunctionDatabase.BSimError;
|
||||||
import ghidra.features.bsim.query.FunctionDatabase.ErrorCategory;
|
import ghidra.features.bsim.query.FunctionDatabase.ErrorCategory;
|
||||||
import ghidra.features.bsim.query.FunctionDatabase.Status;
|
|
||||||
import ghidra.features.bsim.query.client.Configuration;
|
import ghidra.features.bsim.query.client.Configuration;
|
||||||
import ghidra.features.bsim.query.client.tables.ExeTable.ExeTableOrderColumn;
|
import ghidra.features.bsim.query.client.tables.ExeTable.ExeTableOrderColumn;
|
||||||
import ghidra.features.bsim.query.description.*;
|
import ghidra.features.bsim.query.description.*;
|
||||||
|
@ -52,7 +50,6 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
// FIXME: May need to use Msg.showError for popup messages in GUI workbench case
|
// FIXME: May need to use Msg.showError for popup messages in GUI workbench case
|
||||||
|
|
||||||
private final BSimServerInfo bsimServerInfo; // may be null
|
private final BSimServerInfo bsimServerInfo; // may be null
|
||||||
private final String connectingUserName;
|
|
||||||
|
|
||||||
private FunctionDatabase querydb;
|
private FunctionDatabase querydb;
|
||||||
|
|
||||||
|
@ -61,14 +58,36 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
* @param bsimServerInfo the BSim database server info. May be {@code null} if use limited to
|
* @param bsimServerInfo the BSim database server info. May be {@code null} if use limited to
|
||||||
* signature and update generation only (based upon configuration template).
|
* signature and update generation only (based upon configuration template).
|
||||||
* @param connectingUserName user name to use for BSim server authentication. May be null if
|
* @param connectingUserName user name to use for BSim server authentication. May be null if
|
||||||
* not required or default should be used (see {@link ClientUtil#getUserName()}).
|
* not required or default should be used (see {@link ClientUtil#getUserName()}). If specified
|
||||||
* @throws MalformedURLException if the given URL string cannot be parsed
|
* a new {@link BSimServerInfo} instance will be created with the user information set. This
|
||||||
|
* argument is ignored if DB user specified by {@code bsimServerInfo}.
|
||||||
*/
|
*/
|
||||||
public BulkSignatures(BSimServerInfo bsimServerInfo, String connectingUserName)
|
public BulkSignatures(BSimServerInfo bsimServerInfo, String connectingUserName) {
|
||||||
throws MalformedURLException {
|
if (bsimServerInfo != null && !StringUtils.isBlank(connectingUserName)) {
|
||||||
|
if (!bsimServerInfo.hasDefaultLogin()) {
|
||||||
|
String username = bsimServerInfo.getUserName();
|
||||||
|
if (!username.equals(connectingUserName)) {
|
||||||
|
Msg.warn(this, "BSim DB server info specifies user '" + username +
|
||||||
|
"'. Ignoring user name option: '" + connectingUserName + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bsimServerInfo = new BSimServerInfo(bsimServerInfo.getDBType(), connectingUserName,
|
||||||
|
bsimServerInfo.getServerName(), bsimServerInfo.getPort(),
|
||||||
|
bsimServerInfo.getDBName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.bsimServerInfo = bsimServerInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param bsimServerInfo the BSim database server info. May be {@code null} if use limited to
|
||||||
|
* signature and update generation only (based upon configuration template). If specified,
|
||||||
|
* this object will convey the connecting user name.
|
||||||
|
*/
|
||||||
|
public BulkSignatures(BSimServerInfo bsimServerInfo) {
|
||||||
this.bsimServerInfo = bsimServerInfo;
|
this.bsimServerInfo = bsimServerInfo;
|
||||||
this.connectingUserName =
|
|
||||||
connectingUserName != null ? connectingUserName : ClientUtil.getUserName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkBSimServerOperation() {
|
private void checkBSimServerOperation() {
|
||||||
|
@ -93,9 +112,6 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
checkBSimServerOperation();
|
checkBSimServerOperation();
|
||||||
|
|
||||||
querydb = BSimClientFactory.buildClient(bsimServerInfo, async);
|
querydb = BSimClientFactory.buildClient(bsimServerInfo, async);
|
||||||
if (querydb.getStatus() == Status.Unconnected) { // may have previously connected
|
|
||||||
querydb.setUserName(connectingUserName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!querydb.initialize()) {
|
if (!querydb.initialize()) {
|
||||||
throw new IOException(querydb.getLastError().message);
|
throw new IOException(querydb.getLastError().message);
|
||||||
|
@ -103,7 +119,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
|
|
||||||
DatabaseInformation info = querydb.getInfo();
|
DatabaseInformation info = querydb.getInfo();
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
if (lastError != null && lastError.category == ErrorCategory.Nodatabase) {
|
if (lastError != null && lastError.category == ErrorCategory.Nodatabase) {
|
||||||
throw new IOException(lastError.message);
|
throw new IOException(lastError.message);
|
||||||
}
|
}
|
||||||
|
@ -190,7 +206,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (insertreq.execute(querydb) == null) {
|
if (insertreq.execute(querydb) == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
if ((lastError.category == ErrorCategory.Format) ||
|
if ((lastError.category == ErrorCategory.Format) ||
|
||||||
(lastError.category == ErrorCategory.Nonfatal)) {
|
(lastError.category == ErrorCategory.Nonfatal)) {
|
||||||
Msg.warn(this, file.getName() + ": " + lastError.message);
|
Msg.warn(this, file.getName() + ": " + lastError.message);
|
||||||
|
@ -216,7 +232,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
loadSignatureXml(file, update.manage);
|
loadSignatureXml(file, update.manage);
|
||||||
ResponseUpdate respup = update.execute(querydb);
|
ResponseUpdate respup = update.execute(querydb);
|
||||||
if (respup == null) {
|
if (respup == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
if ((lastError.category == ErrorCategory.Format) ||
|
if ((lastError.category == ErrorCategory.Format) ||
|
||||||
(lastError.category == ErrorCategory.Nonfatal)) {
|
(lastError.category == ErrorCategory.Nonfatal)) {
|
||||||
Msg.warn(this, file.getName() + ": " + lastError.message);
|
Msg.warn(this, file.getName() + ": " + lastError.message);
|
||||||
|
@ -400,9 +416,6 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
checkBSimServerOperation();
|
checkBSimServerOperation();
|
||||||
|
|
||||||
querydb = BSimClientFactory.buildClient(bsimServerInfo, true);
|
querydb = BSimClientFactory.buildClient(bsimServerInfo, true);
|
||||||
if (querydb.getStatus() == Status.Unconnected) { // may have previously connected
|
|
||||||
querydb.setUserName(connectingUserName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Should this output differ for command-line vs workbench? debug only?
|
// TODO: Should this output differ for command-line vs workbench? debug only?
|
||||||
try {
|
try {
|
||||||
|
@ -533,7 +546,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
establishQueryServerConnection(true);
|
establishQueryServerConnection(true);
|
||||||
ResponseDelete respdel = query.execute(querydb);
|
ResponseDelete respdel = query.execute(querydb);
|
||||||
if (respdel == null) {
|
if (respdel == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
throw new LSHException("Could not perform delete: " + lastError.message);
|
throw new LSHException("Could not perform delete: " + lastError.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,7 +574,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
query.doRebuild = false;
|
query.doRebuild = false;
|
||||||
ResponseAdjustIndex response = query.execute(querydb);
|
ResponseAdjustIndex response = query.execute(querydb);
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
throw new LSHException("Could not drop index: " + lastError.message);
|
throw new LSHException("Could not drop index: " + lastError.message);
|
||||||
}
|
}
|
||||||
String dbDetail = "for database " + info.databasename + " (" + bsimServerInfo + ")";
|
String dbDetail = "for database " + info.databasename + " (" + bsimServerInfo + ")";
|
||||||
|
@ -590,7 +603,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
System.out.println("Starting rebuild ...");
|
System.out.println("Starting rebuild ...");
|
||||||
ResponseAdjustIndex response = query.execute(querydb);
|
ResponseAdjustIndex response = query.execute(querydb);
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
throw new LSHException("Could not rebuild index: " + lastError.message);
|
throw new LSHException("Could not rebuild index: " + lastError.message);
|
||||||
}
|
}
|
||||||
String dbDetail = "for database " + info.databasename + " (" + bsimServerInfo + ")";
|
String dbDetail = "for database " + info.databasename + " (" + bsimServerInfo + ")";
|
||||||
|
@ -617,7 +630,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
PrewarmRequest request = new PrewarmRequest();
|
PrewarmRequest request = new PrewarmRequest();
|
||||||
ResponsePrewarm response = request.execute(querydb);
|
ResponsePrewarm response = request.execute(querydb);
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
throw new LSHException("Prewarm failed: " + lastError.message);
|
throw new LSHException("Prewarm failed: " + lastError.message);
|
||||||
}
|
}
|
||||||
String dbDetail = "for database " + info.databasename + " (" + bsimServerInfo + ")";
|
String dbDetail = "for database " + info.databasename + " (" + bsimServerInfo + ")";
|
||||||
|
@ -662,7 +675,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
|
|
||||||
ResponseExe response = exeQuery.execute(querydb);
|
ResponseExe response = exeQuery.execute(querydb);
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
throw new LSHException("Could not perform getexeinfo: " + lastError.message);
|
throw new LSHException("Could not perform getexeinfo: " + lastError.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,7 +748,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
req.description = description;
|
req.description = description;
|
||||||
ResponseInfo resp = req.execute(querydb);
|
ResponseInfo resp = req.execute(querydb);
|
||||||
if (resp == null) {
|
if (resp == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
throw new LSHException("Could not change metadata: " + lastError.message);
|
throw new LSHException("Could not change metadata: " + lastError.message);
|
||||||
}
|
}
|
||||||
info = resp.info;
|
info = resp.info;
|
||||||
|
@ -764,7 +777,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
|
|
||||||
ResponseInfo resp = req.execute(querydb);
|
ResponseInfo resp = req.execute(querydb);
|
||||||
if (resp == null) {
|
if (resp == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
throw new LSHException("Could not install new category: " + lastError.message);
|
throw new LSHException("Could not install new category: " + lastError.message);
|
||||||
}
|
}
|
||||||
info = resp.info;
|
info = resp.info;
|
||||||
|
@ -798,7 +811,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
req.tag_name = dequoteString(tagName);
|
req.tag_name = dequoteString(tagName);
|
||||||
ResponseInfo resp = req.execute(querydb);
|
ResponseInfo resp = req.execute(querydb);
|
||||||
if (resp == null) {
|
if (resp == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
throw new LSHException(lastError.message);
|
throw new LSHException(lastError.message);
|
||||||
}
|
}
|
||||||
info = resp.info;
|
info = resp.info;
|
||||||
|
@ -859,7 +872,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
while (count != 0) {
|
while (count != 0) {
|
||||||
ResponsePair responsePair = query.execute(querydb);
|
ResponsePair responsePair = query.execute(querydb);
|
||||||
if (responsePair == null) {
|
if (responsePair == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
throw new LSHException(lastError.message);
|
throw new LSHException(lastError.message);
|
||||||
}
|
}
|
||||||
for (PairNote note : responsePair.notes) {
|
for (PairNote note : responsePair.notes) {
|
||||||
|
@ -893,7 +906,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
establishQueryServerConnection(true);
|
establishQueryServerConnection(true);
|
||||||
ResponseName resp = query.execute(querydb);
|
ResponseName resp = query.execute(querydb);
|
||||||
if (resp == null) {
|
if (resp == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
throw new LSHException(lastError.message);
|
throw new LSHException(lastError.message);
|
||||||
}
|
}
|
||||||
resp.printRaw(outStream, querydb.getLSHVectorFactory(), 0);
|
resp.printRaw(outStream, querydb.getLSHVectorFactory(), 0);
|
||||||
|
@ -941,7 +954,7 @@ public class BulkSignatures implements AutoCloseable {
|
||||||
query.fillinCallgraph = info.trackcallgraph;
|
query.fillinCallgraph = info.trackcallgraph;
|
||||||
ResponseName responseName = query.execute(querydb);
|
ResponseName responseName = query.execute(querydb);
|
||||||
if (responseName == null) {
|
if (responseName == null) {
|
||||||
Error lastError = querydb.getLastError();
|
BSimError lastError = querydb.getLastError();
|
||||||
throw new LSHException(lastError.message);
|
throw new LSHException(lastError.message);
|
||||||
}
|
}
|
||||||
if (!responseName.uniqueexecutable) {
|
if (!responseName.uniqueexecutable) {
|
||||||
|
|
|
@ -20,8 +20,10 @@ import java.util.*;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import docking.DialogComponentProvider;
|
||||||
import docking.DockingWindowManager;
|
import docking.DockingWindowManager;
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
import docking.widgets.textfield.GFormattedTextField;
|
||||||
import ghidra.app.services.ProgramManager;
|
import ghidra.app.services.ProgramManager;
|
||||||
import ghidra.features.bsim.gui.*;
|
import ghidra.features.bsim.gui.*;
|
||||||
import ghidra.features.bsim.gui.overview.BSimOverviewProvider;
|
import ghidra.features.bsim.gui.overview.BSimOverviewProvider;
|
||||||
|
@ -90,9 +92,11 @@ public class BSimSearchPluginScreenShots extends GhidraScreenShotGenerator {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testManageServersDialog() {
|
public void testManageServersDialog() {
|
||||||
addTestServer(new BSimServerInfo(DBType.postgres, "100.50.123.5", 123, "testDB"));
|
addTestServer(
|
||||||
addTestServer(new BSimServerInfo(DBType.postgres, "100.50.123.5", 134, "anotherDB"));
|
new BSimServerInfo(DBType.postgres, "mylogin", "100.50.123.5", 123, "testDB"));
|
||||||
addTestServer(new BSimServerInfo(DBType.file, "100.50.123.5", 134, "/bsim/database1"));
|
addTestServer(
|
||||||
|
new BSimServerInfo(DBType.postgres, "mylogin", "100.50.123.5", 134, "anotherDB"));
|
||||||
|
addTestServer(new BSimServerInfo("/bsim/database1"));
|
||||||
|
|
||||||
DockingActionIf action = getAction(plugin, "Manage BSim Servers");
|
DockingActionIf action = getAction(plugin, "Manage BSim Servers");
|
||||||
performAction(action, false);
|
performAction(action, false);
|
||||||
|
@ -106,7 +110,11 @@ public class BSimSearchPluginScreenShots extends GhidraScreenShotGenerator {
|
||||||
public void testAddServerDialog() {
|
public void testAddServerDialog() {
|
||||||
CreateBsimServerInfoDialog dialog = new CreateBsimServerInfoDialog();
|
CreateBsimServerInfoDialog dialog = new CreateBsimServerInfoDialog();
|
||||||
runSwingLater(() -> DockingWindowManager.showDialog(dialog));
|
runSwingLater(() -> DockingWindowManager.showDialog(dialog));
|
||||||
waitForSwing();
|
DialogComponentProvider entryDialog = waitForDialogComponent("Add BSim Server");
|
||||||
|
GFormattedTextField userField =
|
||||||
|
(GFormattedTextField) findComponentByName(entryDialog, "User");
|
||||||
|
userField.setText("mylogin");
|
||||||
|
userField.setDefaultValue("mylogin");
|
||||||
captureDialog(dialog);
|
captureDialog(dialog);
|
||||||
dialog.close();
|
dialog.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -178,7 +178,7 @@ public class BSimSearchPluginTest extends AbstractBSimPluginTest {
|
||||||
private FunctionDatabase database;
|
private FunctionDatabase database;
|
||||||
|
|
||||||
public TestBSimServerInfo(FunctionDatabase database) {
|
public TestBSimServerInfo(FunctionDatabase database) {
|
||||||
super(DBType.postgres, "0.0.0.0", 123, "testDB");
|
super(DBType.postgres, null, "0.0.0.0", 123, "testDB");
|
||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ import org.junit.*;
|
||||||
|
|
||||||
import ghidra.features.bsim.query.*;
|
import ghidra.features.bsim.query.*;
|
||||||
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
import ghidra.features.bsim.query.BSimServerInfo.DBType;
|
||||||
import ghidra.features.bsim.query.FunctionDatabase.Error;
|
import ghidra.features.bsim.query.FunctionDatabase.BSimError;
|
||||||
import ghidra.features.bsim.query.description.DatabaseInformation;
|
import ghidra.features.bsim.query.description.DatabaseInformation;
|
||||||
import ghidra.features.bsim.query.file.BSimH2FileDBConnectionManager.BSimH2FileDataSource;
|
import ghidra.features.bsim.query.file.BSimH2FileDBConnectionManager.BSimH2FileDataSource;
|
||||||
import ghidra.features.bsim.query.protocol.CreateDatabase;
|
import ghidra.features.bsim.query.protocol.CreateDatabase;
|
||||||
|
@ -68,7 +68,7 @@ public class BSimH2DatabaseManagerTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
}
|
}
|
||||||
|
|
||||||
private BSimServerInfo getBsimServerInfo(String name) {
|
private BSimServerInfo getBsimServerInfo(String name) {
|
||||||
return new BSimServerInfo(DBType.file, null, -1, getDbName(name));
|
return new BSimServerInfo(getDbName(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
private BSimServerInfo createDatabase(String databaseName) {
|
private BSimServerInfo createDatabase(String databaseName) {
|
||||||
|
@ -103,7 +103,7 @@ public class BSimH2DatabaseManagerTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
ResponseInfo response = command.execute(h2Database);
|
ResponseInfo response = command.execute(h2Database);
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
if (expectedError != null) {
|
if (expectedError != null) {
|
||||||
Error lastError = h2Database.getLastError();
|
BSimError lastError = h2Database.getLastError();
|
||||||
assertNotNull(lastError);
|
assertNotNull(lastError);
|
||||||
assertTrue(lastError.message.contains(expectedError));
|
assertTrue(lastError.message.contains(expectedError));
|
||||||
}
|
}
|
||||||
|
@ -186,7 +186,7 @@ public class BSimH2DatabaseManagerTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
BSimServerInfo serverInfo = getBsimServerInfo("test");
|
BSimServerInfo serverInfo = getBsimServerInfo("test");
|
||||||
try (FunctionDatabase fdb = serverInfo.getFunctionDatabase(false)) {
|
try (FunctionDatabase fdb = serverInfo.getFunctionDatabase(false)) {
|
||||||
assertFalse(fdb.initialize());
|
assertFalse(fdb.initialize());
|
||||||
Error lastError = fdb.getLastError();
|
BSimError lastError = fdb.getLastError();
|
||||||
assertNotNull(lastError);
|
assertNotNull(lastError);
|
||||||
assertTrue(lastError.message.startsWith("Database does not exist: "));
|
assertTrue(lastError.message.startsWith("Database does not exist: "));
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ import ghidra.app.util.headless.HeadlessOptions;
|
||||||
import ghidra.features.bsim.gui.filters.ExecutableCategoryBSimFilterType;
|
import ghidra.features.bsim.gui.filters.ExecutableCategoryBSimFilterType;
|
||||||
import ghidra.features.bsim.gui.filters.HasNamedChildBSimFilterType;
|
import ghidra.features.bsim.gui.filters.HasNamedChildBSimFilterType;
|
||||||
import ghidra.features.bsim.query.*;
|
import ghidra.features.bsim.query.*;
|
||||||
import ghidra.features.bsim.query.FunctionDatabase.Error;
|
import ghidra.features.bsim.query.FunctionDatabase.BSimError;
|
||||||
import ghidra.features.bsim.query.client.tables.ExeTable.ExeTableOrderColumn;
|
import ghidra.features.bsim.query.client.tables.ExeTable.ExeTableOrderColumn;
|
||||||
import ghidra.features.bsim.query.description.*;
|
import ghidra.features.bsim.query.description.*;
|
||||||
import ghidra.features.bsim.query.ingest.BSimLaunchable;
|
import ghidra.features.bsim.query.ingest.BSimLaunchable;
|
||||||
|
@ -264,7 +264,7 @@ public class BSimServerTest {
|
||||||
|
|
||||||
private static void testForError(QueryResponseRecord response) throws LSHException {
|
private static void testForError(QueryResponseRecord response) throws LSHException {
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
Error lastError = client.getLastError();
|
BSimError lastError = client.getLastError();
|
||||||
if (lastError == null) {
|
if (lastError == null) {
|
||||||
throw new LSHException("Unknown error");
|
throw new LSHException("Unknown error");
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -106,11 +106,6 @@ public class FunctionDatabaseTestDouble implements SQLFunctionDatabase {
|
||||||
return ClientUtil.getUserName();
|
return ClientUtil.getUserName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUserName(String userName) {
|
|
||||||
// Currently not implemented
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getURLString() {
|
public String getURLString() {
|
||||||
return urlString;
|
return urlString;
|
||||||
|
@ -141,8 +136,8 @@ public class FunctionDatabaseTestDouble implements SQLFunctionDatabase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Error getLastError() {
|
public BSimError getLastError() {
|
||||||
return new Error(ErrorCategory.Unused, errorString);
|
return new BSimError(ErrorCategory.Unused, errorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setErrorString(String errorString) {
|
void setErrorString(String errorString) {
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -23,7 +23,7 @@ public class TestBSimServerInfo extends BSimServerInfo {
|
||||||
private FunctionDatabase database;
|
private FunctionDatabase database;
|
||||||
|
|
||||||
public TestBSimServerInfo(FunctionDatabase database) {
|
public TestBSimServerInfo(FunctionDatabase database) {
|
||||||
super(DBType.postgres, "100.50.123.5", 123, "testDB");
|
super(DBType.postgres, null, "100.50.123.5", 123, "testDB");
|
||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -38,7 +38,8 @@ public class PasswordDialog extends DialogComponentProvider {
|
||||||
private JPasswordField passwordField;
|
private JPasswordField passwordField;
|
||||||
private JComboBox<String> choiceCB;
|
private JComboBox<String> choiceCB;
|
||||||
private JCheckBox anonymousAccess;
|
private JCheckBox anonymousAccess;
|
||||||
boolean okPressed = false;
|
private boolean okPressed = false;
|
||||||
|
private String defaultUserID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new PasswordDialog.
|
* Construct a new PasswordDialog.
|
||||||
|
@ -47,7 +48,7 @@ public class PasswordDialog extends DialogComponentProvider {
|
||||||
* @param serverName name of server or keystore pathname
|
* @param serverName name of server or keystore pathname
|
||||||
* @param passPrompt password prompt to show in the dialog; may be null, in which case
|
* @param passPrompt password prompt to show in the dialog; may be null, in which case
|
||||||
* "Password:" is displayed next to the password field
|
* "Password:" is displayed next to the password field
|
||||||
* @param namePrompt name prompt to show in the dialog, if null a name will not be prompted for.
|
* @param userIdPrompt User ID / Name prompt to show in the dialog, if null a name will not be prompted for.
|
||||||
* @param defaultUserID default name when prompting for a name
|
* @param defaultUserID default name when prompting for a name
|
||||||
* @param choicePrompt namePrompt name prompt to show in the dialog, if null a name will not be prompted for.
|
* @param choicePrompt namePrompt name prompt to show in the dialog, if null a name will not be prompted for.
|
||||||
* @param choices array of choices to present if choicePrompt is not null
|
* @param choices array of choices to present if choicePrompt is not null
|
||||||
|
@ -55,9 +56,9 @@ public class PasswordDialog extends DialogComponentProvider {
|
||||||
* @param includeAnonymousOption true signals to add a checkbox to request anonymous login
|
* @param includeAnonymousOption true signals to add a checkbox to request anonymous login
|
||||||
*/
|
*/
|
||||||
public PasswordDialog(String title, String serverType, String serverName, String passPrompt,
|
public PasswordDialog(String title, String serverType, String serverName, String passPrompt,
|
||||||
String namePrompt, String defaultUserID, String choicePrompt, String[] choices,
|
String userIdPrompt, String defaultUserID, String choicePrompt, String[] choices,
|
||||||
int defaultChoice, boolean includeAnonymousOption) {
|
int defaultChoice, boolean includeAnonymousOption) {
|
||||||
this(title, serverType, serverName, passPrompt, namePrompt, defaultUserID);
|
this(title, serverType, serverName, passPrompt, userIdPrompt, defaultUserID);
|
||||||
if (choicePrompt != null) {
|
if (choicePrompt != null) {
|
||||||
workPanel.add(new GLabel(choicePrompt));
|
workPanel.add(new GLabel(choicePrompt));
|
||||||
choiceCB = new GComboBox<>(choices);
|
choiceCB = new GComboBox<>(choices);
|
||||||
|
@ -94,12 +95,12 @@ public class PasswordDialog extends DialogComponentProvider {
|
||||||
* @param serverName name of server or keystore pathname
|
* @param serverName name of server or keystore pathname
|
||||||
* @param passPrompt password prompt to show in the dialog; may be null, in which case
|
* @param passPrompt password prompt to show in the dialog; may be null, in which case
|
||||||
* "Password:" is displayed next to the password field
|
* "Password:" is displayed next to the password field
|
||||||
* @param namePrompt name prompt to show in the dialog, if null a name will not be prompted for.
|
* @param userIdPrompt User ID / Name prompt to show in the dialog, if null a name will not be prompted for.
|
||||||
* @param defaultUserID default name when prompting for a name
|
* @param defaultUserID default name when prompting for a name
|
||||||
*/
|
*/
|
||||||
public PasswordDialog(String title, String serverType, String serverName, String passPrompt,
|
public PasswordDialog(String title, String serverType, String serverName, String passPrompt,
|
||||||
String namePrompt, String defaultUserID) {
|
String userIdPrompt, String defaultUserID) {
|
||||||
this(title, serverType, serverName, passPrompt, namePrompt, defaultUserID, true);
|
this(title, serverType, serverName, passPrompt, userIdPrompt, defaultUserID, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,14 +110,17 @@ public class PasswordDialog extends DialogComponentProvider {
|
||||||
* @param serverName name of server or keystore pathname
|
* @param serverName name of server or keystore pathname
|
||||||
* @param passPrompt password prompt to show in the dialog; may be null, in which case
|
* @param passPrompt password prompt to show in the dialog; may be null, in which case
|
||||||
* "Password:" is displayed next to the password field
|
* "Password:" is displayed next to the password field
|
||||||
* @param namePrompt name prompt to show in the dialog, if null a name will not be prompted for.
|
* @param userIdPrompt User ID / Name prompt to show in the dialog, if null a name will not be prompted for.
|
||||||
* @param defaultUserID default name when prompting for a name
|
* @param defaultUserID default name when prompting for a name
|
||||||
* @param hasMessages true if the client will set messages on this dialog. If true, the
|
* @param hasMessages true if the client will set messages on this dialog. If true, the
|
||||||
* dialog's minimum size will be increased
|
* dialog's minimum size will be increased
|
||||||
*/
|
*/
|
||||||
public PasswordDialog(String title, String serverType, String serverName, String passPrompt,
|
public PasswordDialog(String title, String serverType, String serverName, String passPrompt,
|
||||||
String namePrompt, String defaultUserID, boolean hasMessages) {
|
String userIdPrompt, String defaultUserID, boolean hasMessages) {
|
||||||
super(title, true);
|
super(title, true);
|
||||||
|
|
||||||
|
this.defaultUserID = defaultUserID;
|
||||||
|
|
||||||
setRememberSize(false);
|
setRememberSize(false);
|
||||||
setTransient(true);
|
setTransient(true);
|
||||||
|
|
||||||
|
@ -132,8 +136,8 @@ public class PasswordDialog extends DialogComponentProvider {
|
||||||
workPanel.add(new GLabel(serverName));
|
workPanel.add(new GLabel(serverName));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (namePrompt != null) {
|
if (userIdPrompt != null) {
|
||||||
workPanel.add(new GLabel(namePrompt));
|
workPanel.add(new GLabel(userIdPrompt));
|
||||||
nameField = new JTextField(defaultUserID, 16);
|
nameField = new JTextField(defaultUserID, 16);
|
||||||
nameField.setName("NAME-ENTRY-COMPONENT");
|
nameField.setName("NAME-ENTRY-COMPONENT");
|
||||||
workPanel.add(nameField);
|
workPanel.add(nameField);
|
||||||
|
@ -237,11 +241,11 @@ public class PasswordDialog extends DialogComponentProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the user ID entered in the password field
|
* Return the user ID / Name entered in the password field
|
||||||
* @return the user ID entered in the password field
|
* @return the user ID / Name entered in the password field
|
||||||
*/
|
*/
|
||||||
public String getUserID() {
|
public String getUserID() {
|
||||||
return nameField != null ? nameField.getText().trim() : null;
|
return nameField != null ? nameField.getText().trim() : defaultUserID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -16,11 +16,12 @@
|
||||||
package ghidra.framework.client;
|
package ghidra.framework.client;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.net.Authenticator;
|
import java.net.*;
|
||||||
import java.net.PasswordAuthentication;
|
|
||||||
|
|
||||||
import javax.security.auth.callback.*;
|
import javax.security.auth.callback.*;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import docking.DockingWindowManager;
|
import docking.DockingWindowManager;
|
||||||
import docking.widgets.*;
|
import docking.widgets.*;
|
||||||
import ghidra.framework.preferences.Preferences;
|
import ghidra.framework.preferences.Preferences;
|
||||||
|
@ -35,23 +36,63 @@ public class DefaultClientAuthenticator extends PopupKeyStorePasswordProvider
|
||||||
private Authenticator authenticator = new Authenticator() {
|
private Authenticator authenticator = new Authenticator() {
|
||||||
@Override
|
@Override
|
||||||
protected PasswordAuthentication getPasswordAuthentication() {
|
protected PasswordAuthentication getPasswordAuthentication() {
|
||||||
Msg.debug(this, "PasswordAuthentication requested for " + getRequestingURL());
|
|
||||||
NameCallback nameCb = null;
|
String serverName = getRequestingHost();
|
||||||
if (!"NO_NAME".equals(getRequestingScheme())) {
|
URL requestingURL = getRequestingURL();
|
||||||
nameCb = new NameCallback("Name: ", ClientUtil.getUserName());
|
|
||||||
|
String pwd = null;
|
||||||
|
String userName = ClientUtil.getUserName();
|
||||||
|
boolean useDefaultUser = true;
|
||||||
|
|
||||||
|
if (requestingURL != null) {
|
||||||
|
String userInfo = requestingURL.getUserInfo();
|
||||||
|
if (userInfo != null) {
|
||||||
|
// Use user info from URL
|
||||||
|
int pwdSep = userInfo.indexOf(':');
|
||||||
|
if (pwdSep < 0) {
|
||||||
|
userName = userInfo;
|
||||||
|
useDefaultUser = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pwd = userInfo.substring(pwdSep + 1);
|
||||||
|
if (pwdSep != 0) {
|
||||||
|
userName = userInfo.substring(0, pwdSep);
|
||||||
|
useDefaultUser = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
URL minimalURL = DefaultClientAuthenticator.getMinimalURL(requestingURL);
|
||||||
|
if (minimalURL != null) {
|
||||||
|
serverName = minimalURL.toExternalForm();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Msg.debug(this, "PasswordAuthentication requested for " + serverName);
|
||||||
|
|
||||||
|
if (pwd != null) {
|
||||||
|
// Requesting URL specified password
|
||||||
|
return new PasswordAuthentication(userName, pwd.toCharArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
NameCallback nameCb = new NameCallback("Name: ", userName);
|
||||||
|
if (!useDefaultUser) {
|
||||||
|
// Prevent modification of user name by password prompting
|
||||||
|
nameCb.setName(userName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prompt for password
|
||||||
String prompt = getRequestingPrompt();
|
String prompt = getRequestingPrompt();
|
||||||
if (prompt == null) {
|
if (StringUtils.isBlank(prompt) || "security".equals(prompt)) {
|
||||||
prompt = "Password:";
|
prompt = "Password:"; // assume dialog will show user name via nameCb
|
||||||
}
|
}
|
||||||
PasswordCallback passCb = new PasswordCallback(prompt, false);
|
PasswordCallback passCb = new PasswordCallback(prompt, false);
|
||||||
try {
|
try {
|
||||||
ServerPasswordPrompt pp = new ServerPasswordPrompt("Connection Authentication",
|
ServerPasswordPrompt pp = new ServerPasswordPrompt("Connection Authentication",
|
||||||
"Server", getRequestingHost(), nameCb, passCb, null, null, null);
|
"Server", serverName, nameCb, passCb, null, null, null);
|
||||||
SystemUtilities.runSwingNow(pp);
|
SystemUtilities.runSwingNow(pp);
|
||||||
if (pp.okWasPressed()) {
|
if (pp.okWasPressed()) {
|
||||||
return new PasswordAuthentication(nameCb != null ? nameCb.getName() : null,
|
return new PasswordAuthentication(nameCb.getName(), passCb.getPassword());
|
||||||
passCb.getPassword());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -61,6 +102,21 @@ public class DefaultClientAuthenticator extends PopupKeyStorePasswordProvider
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produce minimal URL (i.e., protocol, host and port)
|
||||||
|
* @param url request URL
|
||||||
|
* @return minimal URL
|
||||||
|
*/
|
||||||
|
public static URL getMinimalURL(URL url) {
|
||||||
|
try {
|
||||||
|
return new URL(url, "/");
|
||||||
|
}
|
||||||
|
catch (MalformedURLException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Authenticator getAuthenticator() {
|
public Authenticator getAuthenticator() {
|
||||||
return authenticator;
|
return authenticator;
|
||||||
|
@ -165,10 +221,25 @@ public class DefaultClientAuthenticator extends PopupKeyStorePasswordProvider
|
||||||
choicePrompt = choiceCb.getPrompt();
|
choicePrompt = choiceCb.getPrompt();
|
||||||
choices = choiceCb.getChoices();
|
choices = choiceCb.getChoices();
|
||||||
}
|
}
|
||||||
PasswordDialog pwdDialog =
|
|
||||||
new PasswordDialog(title, serverType, serverName, passCb.getPrompt(),
|
String defaultUserName = null;
|
||||||
nameCb != null ? nameCb.getPrompt() : null, getDefaultUserName(), choicePrompt,
|
String namePrompt = null;
|
||||||
choices, getDefaultChoice(), anonymousCb != null);
|
if (nameCb != null) {
|
||||||
|
defaultUserName = nameCb.getName();
|
||||||
|
if (defaultUserName == null) {
|
||||||
|
// Name entry only permitted with name callback where name has not be pre-set
|
||||||
|
defaultUserName = nameCb.getDefaultName();
|
||||||
|
namePrompt = nameCb.getPrompt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (defaultUserName == null) {
|
||||||
|
defaultUserName = getDefaultUserName();
|
||||||
|
}
|
||||||
|
|
||||||
|
PasswordDialog pwdDialog = new PasswordDialog(title, serverType, serverName,
|
||||||
|
passCb.getPrompt(), namePrompt, defaultUserName, choicePrompt, choices,
|
||||||
|
getDefaultChoice(), anonymousCb != null);
|
||||||
|
|
||||||
if (errorMsg != null) {
|
if (errorMsg != null) {
|
||||||
pwdDialog.setErrorText(errorMsg);
|
pwdDialog.setErrorText(errorMsg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -39,38 +39,58 @@ public class HeadlessClientAuthenticator implements ClientAuthenticator {
|
||||||
private final static char[] BADPASSWORD = "".toCharArray();
|
private final static char[] BADPASSWORD = "".toCharArray();
|
||||||
|
|
||||||
private static Object sshPrivateKey;
|
private static Object sshPrivateKey;
|
||||||
private static String userID = ClientUtil.getUserName(); // default username
|
private static String defaultUserName = ClientUtil.getUserName();
|
||||||
private static boolean passwordPromptAllowed;
|
private static boolean passwordPromptAllowed;
|
||||||
|
|
||||||
private Authenticator authenticator = new Authenticator() {
|
private Authenticator authenticator = new Authenticator() {
|
||||||
@Override
|
@Override
|
||||||
protected PasswordAuthentication getPasswordAuthentication() {
|
protected PasswordAuthentication getPasswordAuthentication() {
|
||||||
Msg.debug(this, "PasswordAuthentication requested for " + getRequestingURL());
|
|
||||||
String usage = null;
|
if (defaultUserName == null) {
|
||||||
String prompt = getRequestingPrompt();
|
throw new IllegalStateException("Default user name is unknown");
|
||||||
if ("security".equals(prompt)) {
|
|
||||||
prompt = null; // squash generic "security" prompt
|
|
||||||
}
|
}
|
||||||
URL requestingURL = getRequestingURL();
|
|
||||||
|
String serverName = getRequestingHost();
|
||||||
|
URL requestingURL = getRequestingURL(); // may be null
|
||||||
|
|
||||||
|
String pwd = null;
|
||||||
|
String userName = defaultUserName;
|
||||||
|
|
||||||
if (requestingURL != null) {
|
if (requestingURL != null) {
|
||||||
URL minimalURL = null;
|
String userInfo = requestingURL.getUserInfo();
|
||||||
try {
|
if (userInfo != null) {
|
||||||
minimalURL = new URL(requestingURL, "/");
|
// Use user info from URL
|
||||||
|
int pwdSep = userInfo.indexOf(':');
|
||||||
|
if (pwdSep < 0) {
|
||||||
|
userName = userInfo;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pwd = userInfo.substring(pwdSep + 1);
|
||||||
|
if (pwdSep != 0) {
|
||||||
|
userName = userInfo.substring(0, pwdSep);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (MalformedURLException e) {
|
|
||||||
// ignore
|
URL minimalURL = DefaultClientAuthenticator.getMinimalURL(requestingURL);
|
||||||
|
if (minimalURL != null) {
|
||||||
|
serverName = minimalURL.toExternalForm();
|
||||||
}
|
}
|
||||||
usage = "Access password requested for " +
|
|
||||||
(minimalURL != null ? minimalURL.toExternalForm()
|
|
||||||
: requestingURL.getAuthority());
|
|
||||||
prompt = "Password:";
|
|
||||||
}
|
}
|
||||||
if (prompt == null) {
|
|
||||||
// Assume Ghidra Server access
|
Msg.debug(this, "PasswordAuthentication requested for " + serverName);
|
||||||
String host = getRequestingHost();
|
|
||||||
prompt = (host != null ? (host + " ") : "") + "(" + userID + ") Password:";
|
if (pwd != null) {
|
||||||
|
// Requesting URL specified password
|
||||||
|
return new PasswordAuthentication(userName, pwd.toCharArray());
|
||||||
}
|
}
|
||||||
return new PasswordAuthentication(userID, getPassword(usage, prompt));
|
|
||||||
|
String usage = "Access password requested for " + serverName;
|
||||||
|
String prompt = getRequestingPrompt();
|
||||||
|
if (StringUtils.isBlank(prompt) || "security".equals(prompt)) {
|
||||||
|
prompt = "Password for " + userName +":";
|
||||||
|
}
|
||||||
|
return new PasswordAuthentication(userName, getPassword(usage, prompt));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -85,7 +105,8 @@ public class HeadlessClientAuthenticator implements ClientAuthenticator {
|
||||||
/**
|
/**
|
||||||
* Install headless client authenticator for Ghidra Server
|
* Install headless client authenticator for Ghidra Server
|
||||||
* @param username optional username to be used with a Ghidra Server which
|
* @param username optional username to be used with a Ghidra Server which
|
||||||
* allows username to be specified
|
* allows username to be specified. If null, {@link ClientUtil#getUserName()}
|
||||||
|
* will be used.
|
||||||
* @param keystorePath optional PKI or SSH keystore path. May also be specified
|
* @param keystorePath optional PKI or SSH keystore path. May also be specified
|
||||||
* as resource path for SSH key.
|
* as resource path for SSH key.
|
||||||
* @param allowPasswordPrompt if true the user may be prompted for passwords
|
* @param allowPasswordPrompt if true the user may be prompted for passwords
|
||||||
|
@ -97,7 +118,7 @@ public class HeadlessClientAuthenticator implements ClientAuthenticator {
|
||||||
boolean allowPasswordPrompt) throws IOException {
|
boolean allowPasswordPrompt) throws IOException {
|
||||||
passwordPromptAllowed = allowPasswordPrompt;
|
passwordPromptAllowed = allowPasswordPrompt;
|
||||||
if (username != null) {
|
if (username != null) {
|
||||||
userID = username;
|
defaultUserName = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear existing key store settings
|
// clear existing key store settings
|
||||||
|
@ -175,7 +196,7 @@ public class HeadlessClientAuthenticator implements ClientAuthenticator {
|
||||||
passwordPrompt += "\n";
|
passwordPrompt += "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prompt == null) {
|
if (StringUtils.isBlank(prompt)) {
|
||||||
prompt = "Password:";
|
prompt = "Password:";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,17 +254,39 @@ public class HeadlessClientAuthenticator implements ClientAuthenticator {
|
||||||
anonymousCb.setAnonymousAccessRequested(true);
|
anonymousCb.setAnonymousAccessRequested(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (defaultUserName == null) {
|
||||||
|
throw new IllegalStateException("Default user name is unknown");
|
||||||
|
}
|
||||||
|
|
||||||
if (choiceCb != null) {
|
if (choiceCb != null) {
|
||||||
choiceCb.setSelectedIndex(1);
|
choiceCb.setSelectedIndex(1);
|
||||||
}
|
}
|
||||||
if (nameCb != null && userID != null) {
|
|
||||||
nameCb.setName(userID);
|
String userName = null;
|
||||||
|
if (nameCb != null) {
|
||||||
|
userName = nameCb.getName();
|
||||||
|
if (userName == null) {
|
||||||
|
userName = nameCb.getDefaultName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (userName == null) {
|
||||||
|
userName = defaultUserName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nameCb != null) {
|
||||||
|
nameCb.setName(defaultUserName);
|
||||||
|
}
|
||||||
|
|
||||||
String usage = null;
|
String usage = null;
|
||||||
if (serverName != null) {
|
if (serverName != null) {
|
||||||
usage = serverType + ": " + serverName;
|
usage = serverType + ": " + serverName;
|
||||||
}
|
}
|
||||||
char[] password = getPassword(usage, passCb.getPrompt());
|
|
||||||
|
// Ignore prompt specified by passCb
|
||||||
|
String prompt = "Password for " + userName +":";
|
||||||
|
|
||||||
|
char[] password = getPassword(usage, prompt);
|
||||||
passCb.setPassword(password);
|
passCb.setPassword(password);
|
||||||
return password != null;
|
return password != null;
|
||||||
}
|
}
|
||||||
|
@ -278,7 +321,7 @@ public class HeadlessClientAuthenticator implements ClientAuthenticator {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (nameCb != null) {
|
if (nameCb != null) {
|
||||||
nameCb.setName(userID);
|
nameCb.setName(defaultUserName);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
sshCb.sign(sshPrivateKey);
|
sshCb.sign(sshPrivateKey);
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -687,6 +687,10 @@ public class GhidraURL {
|
||||||
if (StringUtils.isBlank(host)) {
|
if (StringUtils.isBlank(host)) {
|
||||||
throw new IllegalArgumentException("host required");
|
throw new IllegalArgumentException("host required");
|
||||||
}
|
}
|
||||||
|
// TODO: Need to improve checks and use of URL encoding
|
||||||
|
if (host.indexOf('@') >= 0) { // prevent user info with hostname
|
||||||
|
throw new IllegalArgumentException("invalid host name");
|
||||||
|
}
|
||||||
if (StringUtils.isBlank(repositoryName)) {
|
if (StringUtils.isBlank(repositoryName)) {
|
||||||
throw new IllegalArgumentException("repository name required");
|
throw new IllegalArgumentException("repository name required");
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -109,6 +109,9 @@ public class GhidraURLConnection extends URLConnection {
|
||||||
public GhidraURLConnection(URL url, GhidraProtocolHandler protocolHandler)
|
public GhidraURLConnection(URL url, GhidraProtocolHandler protocolHandler)
|
||||||
throws MalformedURLException {
|
throws MalformedURLException {
|
||||||
super(url);
|
super(url);
|
||||||
|
if (url.getUserInfo() != null) {
|
||||||
|
throw new MalformedURLException("User info not supported by Ghidra URLs");
|
||||||
|
}
|
||||||
if (protocolHandler == null) {
|
if (protocolHandler == null) {
|
||||||
throw new IllegalArgumentException("missing required protocol handler");
|
throw new IllegalArgumentException("missing required protocol handler");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue