136 lines
7.4 KiB
C#
136 lines
7.4 KiB
C#
using System;
|
||
using System.IO;
|
||
using System.IO.Pipes;
|
||
using System.Text;
|
||
using System.Threading;
|
||
using System.Web.Script.Serialization;
|
||
using System.Collections.Generic;
|
||
using System.Windows.Forms;
|
||
using Microsoft.Win32;
|
||
|
||
internal static class Bridge {
|
||
const string Host = "online.turkservis.aiturk";
|
||
const string Origin = "chrome-extension://ikcplfhgapaabedillejmggjcabpkolp/";
|
||
const int MaxFrame = 512 * 1024;
|
||
static readonly object OutputLock = new object();
|
||
static readonly JavaScriptSerializer Json = new JavaScriptSerializer { MaxJsonLength = MaxFrame };
|
||
static readonly Encoding Utf8 = new UTF8Encoding(false, true);
|
||
|
||
static string ProductDirectory() {
|
||
string local = Environment.GetEnvironmentVariable("LOCALAPPDATA");
|
||
if (String.IsNullOrEmpty(local) || !Path.IsPathRooted(local))
|
||
local = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||
return Path.Combine(local, "TurkServis", "AITURK-IDE");
|
||
}
|
||
|
||
static byte[] ReadExactly(Stream source, int count, bool eofAllowed) {
|
||
var buffer = new byte[count];
|
||
int offset = 0;
|
||
while (offset < count) {
|
||
int read = source.Read(buffer, offset, count - offset);
|
||
if (read == 0) {
|
||
if (offset == 0 && eofAllowed) return null;
|
||
throw new EndOfStreamException();
|
||
}
|
||
offset += read;
|
||
}
|
||
return buffer;
|
||
}
|
||
|
||
static void WriteFrame(Stream output, string message) {
|
||
byte[] data = Utf8.GetBytes(message);
|
||
if (data.Length > MaxFrame) throw new InvalidDataException();
|
||
lock (OutputLock) {
|
||
byte[] size = BitConverter.GetBytes(data.Length);
|
||
output.Write(size, 0, size.Length);
|
||
output.Write(data, 0, data.Length);
|
||
output.Flush();
|
||
}
|
||
}
|
||
|
||
[STAThread]
|
||
static int Main(string[] args) {
|
||
if (args.Length == 0 || args[0] == "--install" || args[0] == "--uninstall")
|
||
return Install(args.Length > 0 && args[0] == "--uninstall");
|
||
if (args[0] != Origin) return 2;
|
||
Stream output = Console.OpenStandardOutput();
|
||
try {
|
||
string discoveryPath = Path.Combine(ProductDirectory(), "chrome-bridge.json");
|
||
if (new FileInfo(discoveryPath).Length > 4096) throw new InvalidDataException();
|
||
var discovery = Json.Deserialize<Dictionary<string, object>>(File.ReadAllText(discoveryPath));
|
||
string pipeName = Convert.ToString(discovery["pipe"]);
|
||
string token = Convert.ToString(discovery["token"]);
|
||
if (!System.Text.RegularExpressions.Regex.IsMatch(pipeName, "^aiturk-chrome-[a-f0-9]{32}$") ||
|
||
!System.Text.RegularExpressions.Regex.IsMatch(token, "^[a-f0-9]{64}$")) throw new InvalidDataException();
|
||
using (var pipe = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous)) {
|
||
pipe.Connect(5000);
|
||
var writer = new StreamWriter(pipe, Utf8) { AutoFlush = true };
|
||
writer.WriteLine(Json.Serialize(new { token = token }));
|
||
var reader = new StreamReader(pipe, Utf8, false, 4096, true);
|
||
var receiver = new Thread(() => {
|
||
try {
|
||
// Bounded character-by-character line framing: ReadLine alone
|
||
// would allocate without a cap for a malformed local peer.
|
||
var line = new StringBuilder();
|
||
int value;
|
||
while ((value = reader.Read()) != -1) {
|
||
if (value == '\n') { WriteFrame(output, line.ToString()); line.Clear(); }
|
||
else { line.Append((char)value); if (line.Length > MaxFrame) throw new InvalidDataException(); }
|
||
}
|
||
} catch { }
|
||
Environment.Exit(0);
|
||
});
|
||
receiver.IsBackground = true;
|
||
receiver.Start();
|
||
Stream input = Console.OpenStandardInput();
|
||
while (true) {
|
||
byte[] header = ReadExactly(input, 4, true);
|
||
if (header == null) break;
|
||
uint size = BitConverter.ToUInt32(header, 0);
|
||
if (size == 0 || size > MaxFrame) throw new InvalidDataException();
|
||
string frame = Utf8.GetString(ReadExactly(input, (int)size, false));
|
||
// Normalize JSON so embedded newlines cannot inject pipe frames.
|
||
var message = Json.Deserialize<Dictionary<string, object>>(frame);
|
||
writer.WriteLine(Json.Serialize(message));
|
||
}
|
||
}
|
||
return 0;
|
||
} catch {
|
||
try { WriteFrame(output, Json.Serialize(new { @event = "error", message = "AITURK IDE bağlantısı bulunamadı. Chrome destekli IDE sürümünü açın; ardından Yeniden bağlan düğmesine basın." })); } catch { }
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
static int Install(bool remove) {
|
||
string destination = Path.Combine(ProductDirectory(), "ChromeNativeHost");
|
||
string keyPath = @"Software\Google\Chrome\NativeMessagingHosts\" + Host;
|
||
string message = remove
|
||
? "Chrome bağlantı kaydı kaldırılacak. IDE konuşmaları ve eklenti dosyaları korunur. Devam edilsin mi?"
|
||
: "AITURK Chrome bağlantısı bu Windows kullanıcısı için kurulacak. Yalnızca AITURK eklentisi, açık IDE'deki konuşmaları okuyup mesaj gönderebilecek. Yönetici yetkisi gerekmez. Devam edilsin mi?";
|
||
if (MessageBox.Show(message, "AITURK Chrome Bağlantısı", MessageBoxButtons.YesNo, MessageBoxIcon.Information) != DialogResult.Yes) return 0;
|
||
try {
|
||
if (remove) {
|
||
Registry.CurrentUser.DeleteSubKey(keyPath, false);
|
||
MessageBox.Show("Chrome bağlantı kaydı kaldırıldı. Dosyalar ve konuşmalar korundu.", "AITURK");
|
||
return 0;
|
||
}
|
||
Directory.CreateDirectory(destination);
|
||
string target = Path.Combine(destination, "AiturkChromeBridge.exe");
|
||
string source = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
||
if (!String.Equals(Path.GetFullPath(source), Path.GetFullPath(target), StringComparison.OrdinalIgnoreCase))
|
||
File.Copy(source, target, true);
|
||
string manifest = Path.Combine(destination, Host + ".json");
|
||
File.WriteAllText(manifest, Json.Serialize(new {
|
||
name = Host, description = "AITURK IDE Chrome bridge", path = target,
|
||
type = "stdio", allowed_origins = new[] { Origin }
|
||
}), new UTF8Encoding(false));
|
||
using (RegistryKey registry = Registry.CurrentUser.CreateSubKey(keyPath)) registry.SetValue("", manifest);
|
||
MessageBox.Show("Bağlantı kuruldu.\n\n1. Chrome destekli AITURK IDE'yi açın.\n2. Chrome'da chrome://extensions sayfasını açın.\n3. Geliştirici modunu açıp Paketlenmemiş öğe yükle ile ZIP içindeki extension klasörünü seçin.\n4. AITURK simgesine basın.\n\nEklenti klasörünü silmeyin veya taşımayın.", "AITURK Chrome hazır");
|
||
return 0;
|
||
} catch (Exception error) {
|
||
MessageBox.Show("Kurulum tamamlanamadı. Chrome yan panelini kapatıp tekrar deneyin.\n" + error.Message, "AITURK", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return 1;
|
||
}
|
||
}
|
||
}
|