mirror of
https://github.com/awatertrevi/xamarin-neo4j.git
synced 2026-09-22 09:05:29 +00:00
wrapping up
This commit is contained in:
@@ -27,7 +27,7 @@
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>nl.resoftware.pocketgraph</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0.1</string>
|
||||
<string>1.0.2</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>CFBundleName</key>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// NativeTrustManager.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 14-03-2022
|
||||
//
|
||||
// © Xamarin.Neo4j.iOS
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Neo4j.Driver;
|
||||
using Security;
|
||||
|
||||
namespace Xamarin.Neo4j
|
||||
{
|
||||
public class NativeTrustManager : TrustManager
|
||||
{
|
||||
public override bool ValidateServerCertificate(Uri uri, X509Certificate2 certificate, X509Chain chain,
|
||||
SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
using (var cert = new SecCertificate(certificate))
|
||||
using (var policy = SecPolicy.CreateSslPolicy(true, uri.Host))
|
||||
using (var trustHandler = new SecTrust(cert, policy))
|
||||
{
|
||||
if (!trustHandler.Evaluate(out var error))
|
||||
throw new Exception(error.ToString());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// TrustManagerService.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 14-03-2022
|
||||
//
|
||||
// © Xamarin.Neo4j.iOS
|
||||
//
|
||||
|
||||
using Neo4j.Driver;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Neo4j.iOS.Services;
|
||||
using Xamarin.Neo4j.Services;
|
||||
|
||||
[assembly: Dependency(typeof(TrustManagerService))]
|
||||
namespace Xamarin.Neo4j.iOS.Services
|
||||
{
|
||||
public class TrustManagerService : ITrustManagerService
|
||||
{
|
||||
public TrustManager GetNativeTrustManager()
|
||||
{
|
||||
return new NativeTrustManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,9 @@
|
||||
<Compile Include="CustomRenderers\QueryEditorRenderer.cs" />
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="AppDelegate.cs" />
|
||||
<Compile Include="Security\NativeTrustManager.cs" />
|
||||
<Compile Include="Services\ScreenSizeService.cs" />
|
||||
<Compile Include="Services\TrustManagerService.cs" />
|
||||
<None Include="Entitlements.plist" />
|
||||
<None Include="Info.plist" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Neo4j.Controls.LicenseCell">
|
||||
<StackLayout Padding="15, 15, 15, 0">
|
||||
<Label FontAttributes="Bold" TextColor="#4169FF" Text="{Binding Name}">
|
||||
<Label.GestureRecognizers>
|
||||
<TapGestureRecognizer Command="{Binding OpenRepo}" />
|
||||
</Label.GestureRecognizers>
|
||||
</Label>
|
||||
<ContentView Padding="10" BackgroundColor="#D8D8D8">
|
||||
<Label Text="{Binding LicenseText}" />
|
||||
</ContentView>
|
||||
</StackLayout>
|
||||
</ViewCell>
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Xamarin.Neo4j.Controls
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class LicenseCell : ViewCell
|
||||
{
|
||||
public LicenseCell()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,14 +52,16 @@ namespace Xamarin.Neo4j.Controls
|
||||
using (var stream = assembly.GetManifestResourceStream(resourceName))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
var (url, isEncrypted, ignoreTrust) = QueryResult.ConnectionString.ParseHost();
|
||||
|
||||
var result = reader.ReadToEnd();
|
||||
|
||||
result = result.Replace("{{host}}", QueryResult.ConnectionString.Host);
|
||||
result = result.Replace("{{port}}", QueryResult.ConnectionString.Port.ToString());
|
||||
result = result.Replace("{{host}}", url);
|
||||
result = result.Replace("{{database}}", QueryResult.ConnectionString.Database);
|
||||
result = result.Replace("{{username}}", QueryResult.ConnectionString.Username);
|
||||
result = result.Replace("{{password}}", QueryResult.ConnectionString.Password);
|
||||
result = result.Replace("{{encryption}}", QueryResult.ConnectionString.Encrypted ? "ENCRYPTION_ON" : "ENCRYPTION_OFF");
|
||||
result = result.Replace("{{encryption}}", isEncrypted ? "ENCRYPTION_ON" : "ENCRYPTION_OFF");
|
||||
result = result.Replace("{{trust}}", ignoreTrust ? "TRUST_ALL_CERTIFICATES" : "TRUST_SYSTEM_CA_SIGNED_CERTIFICATES");
|
||||
result = result.Replace("{{query}}", QueryResult.Query);
|
||||
result = result.Replace("{{backgroundColor}}", App.Current.RequestedTheme == OSAppTheme.Dark ? "#292C31" : "#FFFFFF");
|
||||
|
||||
|
||||
30
Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Models/License.cs
Normal file
30
Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Models/License.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// License.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 15-03-2022
|
||||
//
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
using Xamarin.Essentials;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Xamarin.Neo4j.Models
|
||||
{
|
||||
public class License
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Repo { get; set; }
|
||||
|
||||
public string LicenseText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Opens the repository in the browser.
|
||||
/// </summary>
|
||||
public ICommand OpenRepo => new Command(() => Launcher.OpenAsync(new Uri(Repo)));
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,25 @@ namespace Xamarin.Neo4j.Models
|
||||
|
||||
public string Host { get; set; }
|
||||
|
||||
public int Port { get; set; }
|
||||
|
||||
public string Username { get; set; }
|
||||
|
||||
public string Password { get; set; }
|
||||
|
||||
public bool Encrypted { get; set; }
|
||||
public Tuple<string, bool, bool> ParseHost()
|
||||
{
|
||||
if (Host.StartsWith("neo4j://"))
|
||||
return new Tuple<string, bool, bool>(Host, false, false);
|
||||
|
||||
if (Host.StartsWith("bolt://"))
|
||||
return new Tuple<string, bool, bool>(Host.Replace("bolt://", "neo4j://"), false, false);
|
||||
|
||||
if (Host.StartsWith("neo4j+s://"))
|
||||
return new Tuple<string, bool, bool>(Host.Replace("neo4j+s://", "neo4j://"), true, false);
|
||||
|
||||
if (Host.StartsWith("neo4j+ssc://"))
|
||||
return new Tuple<string, bool, bool>(Host.Replace("neo4j+ssc://", "neo4j://"), true, true);
|
||||
|
||||
throw new NotSupportedException("Unknown protocol.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,16 +12,6 @@
|
||||
<Entry Text="{Binding Host}" />
|
||||
</StackLayout>
|
||||
|
||||
<StackLayout Spacing="4">
|
||||
<Label Text="Port:" FontAttributes="Bold" FontSize="Small" />
|
||||
<Entry Text="{Binding Port}" Keyboard="Numeric" />
|
||||
</StackLayout>
|
||||
|
||||
<StackLayout Spacing="4">
|
||||
<Label Text="Encryption:" FontAttributes="Bold" FontSize="Small" />
|
||||
<Switch IsToggled="{Binding Encryption}" />
|
||||
</StackLayout>
|
||||
|
||||
<StackLayout Spacing="4">
|
||||
<Label Text="Username:" FontAttributes="Bold" FontSize="Small" />
|
||||
<Entry Text="{Binding Username}" Keyboard="Numeric" />
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:controls="clr-namespace:Xamarin.Neo4j.Controls"
|
||||
Title="Software Licenses"
|
||||
x:Class="Xamarin.Neo4j.Pages.LicensesPage">
|
||||
<ContentPage.Content>
|
||||
<ListView SeparatorVisibility="None" SelectionMode="None" HasUnevenRows="True" ItemsSource="{Binding Licenses}">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<controls:LicenseCell />
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
<ListView.Footer>
|
||||
<ContentView Padding="0, 15, 0, 0" />
|
||||
</ListView.Footer>
|
||||
</ListView>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using Xamarin.Neo4j.ViewModels;
|
||||
|
||||
namespace Xamarin.Neo4j.Pages
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class LicensesPage : ContentPage
|
||||
{
|
||||
public LicensesPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
BindingContext = new LicensesViewModel(Navigation);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@
|
||||
</NavigationPage.TitleView>
|
||||
|
||||
<ContentPage.ToolbarItems>
|
||||
<ToolbarItem Command="{Binding Commands[ExecuteQuery]}">
|
||||
<ToolbarItem Command="{Binding Commands[ExecuteQuery]}" IsEnabled="{Binding CanExecuteQuery}">
|
||||
<ToolbarItem.IconImageSource>
|
||||
<FontImageSource
|
||||
FontFamily="{StaticResource FontAwesomeSolid}"
|
||||
|
||||
@@ -13,9 +13,16 @@
|
||||
</ContentPage.IconImageSource>
|
||||
|
||||
<ContentPage.Content>
|
||||
<ScrollView>
|
||||
<StackLayout Spacing="15" Padding="25">
|
||||
<StackLayout Spacing="15" VerticalOptions="EndAndExpand">
|
||||
<StackLayout VerticalOptions="FillAndExpand">
|
||||
<TableView VerticalOptions="StartAndExpand" Intent="Settings" Background="Transparent">
|
||||
<TableRoot>
|
||||
<TableSection>
|
||||
<TextCell Text="Software Licenses" Command="{Binding Commands[OpenLicensesPage]}" />
|
||||
</TableSection>
|
||||
</TableRoot>
|
||||
</TableView>
|
||||
|
||||
<StackLayout Spacing="15" Margin="25" VerticalOptions="EndAndExpand">
|
||||
<Label Text="A product of" HorizontalOptions="Center" FontAttributes="Italic" FontSize="12" TextColor="{StaticResource SecondaryTextColor}" />
|
||||
<Image Source="resoftware.png" HorizontalOptions="Center" WidthRequest="100">
|
||||
<Image.GestureRecognizers>
|
||||
@@ -24,6 +31,5 @@
|
||||
</Image>
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,9 @@
|
||||
using Neo4j.Driver;
|
||||
|
||||
namespace Xamarin.Neo4j.Services
|
||||
{
|
||||
public interface ITrustManagerService
|
||||
{
|
||||
TrustManager GetNativeTrustManager();
|
||||
}
|
||||
}
|
||||
@@ -16,26 +16,37 @@ using Neo4jClient.Cypher;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Neo4j.Models;
|
||||
using Xamarin.Neo4j.Services;
|
||||
|
||||
[assembly: Dependency(typeof(Neo4jService))]
|
||||
|
||||
namespace Xamarin.Neo4j.Services
|
||||
{
|
||||
public class Neo4jService
|
||||
{
|
||||
private readonly TrustManager _nativeTrustManager;
|
||||
|
||||
public Neo4jService()
|
||||
{
|
||||
var trustManagerService = DependencyService.Get<ITrustManagerService>();
|
||||
|
||||
_nativeTrustManager = trustManagerService.GetNativeTrustManager();
|
||||
}
|
||||
|
||||
private BoltGraphClient GraphClient { get; set; }
|
||||
|
||||
public async Task<bool> EstablishConnection(Neo4jConnectionString connectionString)
|
||||
{
|
||||
try
|
||||
{
|
||||
var boltUri = $"bolt://{connectionString.Host}:{connectionString.Port}";
|
||||
var (url, isEncrypted, ignoreTrust) = connectionString.ParseHost();
|
||||
|
||||
var driver = GraphDatabase.Driver(boltUri,
|
||||
AuthTokens.Basic(connectionString.Username, connectionString.Password),
|
||||
builder =>
|
||||
var driver = GraphDatabase.Driver(url,
|
||||
AuthTokens.Basic(connectionString.Username, connectionString.Password), (config) =>
|
||||
{
|
||||
builder.WithEncryptionLevel(connectionString.Encrypted
|
||||
? EncryptionLevel.Encrypted
|
||||
: EncryptionLevel.None);
|
||||
config.WithEncryptionLevel(isEncrypted ? EncryptionLevel.Encrypted : EncryptionLevel.None);
|
||||
|
||||
if (!ignoreTrust && Device.RuntimePlatform == Device.iOS)
|
||||
config.WithTrustManager(_nativeTrustManager);
|
||||
});
|
||||
|
||||
GraphClient = new BoltGraphClient(driver);
|
||||
|
||||
@@ -25,12 +25,8 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
public class AddConnectionViewModel : ViewModelBase, INotifyPropertyChanged
|
||||
{
|
||||
private bool _encrypted;
|
||||
|
||||
private string _host, _username, _password;
|
||||
|
||||
private int _port;
|
||||
|
||||
private readonly Neo4jService _neo4jService;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
@@ -83,7 +79,6 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
private void InitializeDefaultValues()
|
||||
{
|
||||
Username = "neo4j";
|
||||
Port = 7687;
|
||||
}
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
@@ -98,27 +93,13 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Host = Host,
|
||||
Port = Port,
|
||||
Username = Username,
|
||||
Password = Password,
|
||||
Encrypted = Encrypted
|
||||
Password = Password
|
||||
};
|
||||
}
|
||||
|
||||
#region Bindable Properties
|
||||
|
||||
public bool Encrypted
|
||||
{
|
||||
get => _encrypted;
|
||||
|
||||
set
|
||||
{
|
||||
_encrypted = value;
|
||||
|
||||
OnPropertyChanged(nameof(Encrypted));
|
||||
}
|
||||
}
|
||||
|
||||
public string Host
|
||||
{
|
||||
get => _host;
|
||||
@@ -131,18 +112,6 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public int Port
|
||||
{
|
||||
get => _port;
|
||||
|
||||
set
|
||||
{
|
||||
_port = value;
|
||||
|
||||
OnPropertyChanged(nameof(Port));
|
||||
}
|
||||
}
|
||||
|
||||
public string Username
|
||||
{
|
||||
get => _username;
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// LicensesViewModel.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 15-03-2022
|
||||
//
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Newtonsoft.Json;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Neo4j.Annotations;
|
||||
using License = Xamarin.Neo4j.Models.License;
|
||||
|
||||
namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
public class LicensesViewModel : ViewModelBase, INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private List<License> _licenses;
|
||||
|
||||
public LicensesViewModel(INavigation navigation) : base(navigation)
|
||||
{
|
||||
LoadLicenses();
|
||||
}
|
||||
|
||||
private void LoadLicenses()
|
||||
{
|
||||
var assembly = GetType().GetTypeInfo().Assembly;
|
||||
|
||||
string licenseFile = $"Xamarin.Neo4j.Resources.licenses.json";
|
||||
|
||||
using (var stream = assembly.GetManifestResourceStream(licenseFile))
|
||||
using (var reader = new StreamReader(stream))
|
||||
Licenses = JsonConvert.DeserializeObject<List<License>>(reader.ReadToEnd());
|
||||
}
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
#region Bindable Properties
|
||||
|
||||
public List<License> Licenses
|
||||
{
|
||||
get => _licenses;
|
||||
|
||||
set
|
||||
{
|
||||
_licenses = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,9 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
|
||||
Commands.Add("ExecuteQuery", new Command(async () =>
|
||||
{
|
||||
if (CanExecuteQuery == false)
|
||||
return;
|
||||
|
||||
_connectionString.Database = CurrentDatabase.Name;
|
||||
|
||||
var result = await _neo4jService.ExecuteQuery(Query, _connectionString);
|
||||
@@ -149,6 +152,8 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanExecuteQuery => !string.IsNullOrWhiteSpace(Query) && CurrentDatabase != null;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ using System.Runtime.CompilerServices;
|
||||
using Xamarin.Essentials;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Neo4j.Annotations;
|
||||
using Xamarin.Neo4j.Pages;
|
||||
|
||||
namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
@@ -26,6 +27,11 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
await Launcher.OpenAsync(new Uri("https://resoftware.nl/"));
|
||||
}));
|
||||
|
||||
Commands.Add("OpenLicensesPage", new Command(async () =>
|
||||
{
|
||||
await Navigation.PushAsync(new LicensesPage());
|
||||
}));
|
||||
}
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
|
||||
@@ -30,11 +30,12 @@
|
||||
function draw() {
|
||||
const config = {
|
||||
container_id: "viz",
|
||||
server_url: `bolt://{{host}}:{{port}}`,
|
||||
server_url: `{{host}}`,
|
||||
server_user: `{{username}}`,
|
||||
server_database: `{{database}}`,
|
||||
server_password: `{{password}}`,
|
||||
encrypted: `{{encryption}}`,
|
||||
trust: `{{trust}}`,
|
||||
initial_cypher: `{{query}}`
|
||||
};
|
||||
|
||||
|
||||
@@ -21,5 +21,7 @@
|
||||
<ItemGroup>
|
||||
<None Remove="Visualization\neovis.html" />
|
||||
<EmbeddedResource Include="Visualization\neovis.html" />
|
||||
<None Remove="Resources\licenses.json" />
|
||||
<EmbeddedResource Include="Resources\licenses.json" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user