/// <summary> /// ローカル情報に変換する /// </summary> /// <param name="manifest"></param> /// <returns></returns> private AddonInfomation ConvertToAddonInfo(V1::Manifest manifest) { var addon = new AddonInfomation(); addon.Name.Value = manifest.Name; addon.Author.Value = manifest.Author; addon.Description.Value = manifest.Description; addon.Version.Value = Version.Parse(manifest.Version); addon.Identifier.Value = manifest.Identifier; addon.Permissions.AddRange(manifest.Permissions); addon.HostPermissions.AddRange(manifest.HostPermissions); addon.AutoUpdatePolicy = manifest.AutoUpdatePolicy; addon.Scripts = manifest.Scripts; if (manifest.Icons.ContainsKey("32")) { addon.IconPathRelative.Value = manifest.Icons["32"]; } else { addon.IconPathRelative.Value = manifest.Icons.Select(i => new KeyValuePair <int, string>(int.Parse(i.Key), i.Value)).OrderByDescending(i => i.Key).FirstOrDefault().Value; } addon.TargetAPIVersion.Value = Version.Parse(manifest.TargetAPIVersion); return(addon); }
/// <summary> /// マニフェストを読み込む /// </summary> /// <param name="path"></param> /// <returns></returns> public IAttemptResult <AddonInfomation> LoadManifest(string path) { if (!this.fileIO.Exists(path)) { return(new AttemptResult <AddonInfomation>() { Message = $"指定されたマニフェストファイル({path})が存在しません。" }); } string content; try { content = this.fileIO.OpenRead(path); } catch (Exception e) { this.logger.Error($"マニフェストファイルの読み込みに失敗しました。({path})", e); return(new AttemptResult <AddonInfomation>() { Message = "マニフェストファイルの読み込みに失敗しました。", Exception = e }); } V1::Manifest info; try { info = JsonParser.DeSerialize <V1::Manifest>(content); } catch (Exception e) { this.logger.Error($"マニフェストファイルの解析に失敗しました。({path})", e); return(new AttemptResult <AddonInfomation>() { Message = "マニフェストファイルの解析に失敗しました。", Exception = e }); } IAttemptResult manifestResult = this.CheckManifest(info); if (!manifestResult.IsSucceeded) { this.logger.Error($"不正なマニフェストファイルです。({path},{manifestResult.Message})"); return(new AttemptResult <AddonInfomation>() { Message = manifestResult.Message }); } AddonInfomation addon = this.ConvertToAddonInfo(info); return(new AttemptResult <AddonInfomation>() { IsSucceeded = true, Data = addon }); }
/// <summary> /// アドオンを初期化して実行する /// </summary> /// <param name="packageID"></param> /// <returns></returns> public async Task <IAttemptResult <bool> > InitializeAsync(string packageID, bool isDevMode) { if (!this.storeHandler.IsInstallled(addon => addon.PackageID == packageID)) { return(new AttemptResult <bool>() { Data = false, Message = "インストールされていないアドオンです。アドオンのサイドロードは出来ません。" }); } string manifestPath = Path.Combine(Const::FileFolder.AddonsFolder, packageID, "manifest.json"); IAttemptResult <AddonInfomation> mResult = this.manifestLoader.LoadManifest(manifestPath); if (!mResult.IsSucceeded || mResult.Data is null) { return(new AttemptResult <bool>() { Data = true, Message = "マニフェストファイルの読み込みに失敗しました。", Exception = mResult.Exception }); } AddonInfomation dbData = this.storeHandler.GetAddon(data => data.PackageID == packageID) !; if (!isDevMode) { //アドオンを検証 IAttemptResult checkResult = this.CheckSafety(dbData, mResult.Data); if (!checkResult.IsSucceeded) { this.container.Remove(dbData.ID.Value); return(new AttemptResult <bool>() { Data = true, Message = checkResult.Message, Exception = checkResult.Exception }); } } AddonInfomation addon = this.container.GetAddon(dbData.ID.Value); //DBのIDを対応させる mResult.Data.PackageID.Value = packageID; mResult.Data.ID.Value = dbData.ID.Value; addon.SetData(mResult.Data); //コンテクストを登録 IAddonContext context = AddonContext.CreateInstance(); this.contexts.Contexts.Add(addon.ID.Value, context); await Task.Delay(1); return(new AttemptResult <bool>() { Data = true, IsSucceeded = true }); }
public IAttemptResult Uninstall(int id) { if (!this.storeHandler.IsInstallled(addon => addon.Id == id)) { return(new AttemptResult() { Message = $"アドオン(id:{id})はインストールされていません。" }); } AddonInfomation addon = this.container.GetAddon(id); string addonDir = Path.Combine(FileFolder.AddonsFolder, addon.PackageID.Value); if (this.contexts.Has(id)) { try { this.contexts.Kill(id); } catch (Exception e) { this.logger.Error($"アドオンコンテクストの破棄に失敗しました。(name:{addon.Name.Value})", e); return(new AttemptResult() { Message = "アドオンコンテクストの破棄に失敗しました。", Exception = e }); } } IAttemptResult storeResult = this.storeHandler.Delete(addon => addon.Id == id); if (!storeResult.IsSucceeded) { return(storeResult); } string newName = Path.Combine(FileFolder.AddonsFolder, $"{addon.PackageID}-deleted"); try { this.fileIO.AppendText(Path.Combine(FileFolder.AddonsFolder, Const::AddonConstant.UninstalledAddonsFile), addon.PackageID.Value); } catch (Exception ex) { this.logger.Error("アドオンディレクトリの削除予定処理に失敗しました。", ex); return(new AttemptResult() { Message = "アドオンフォルダーの削除予定処理に失敗しました。", Exception = ex }); } this.container.Remove(id); return(new AttemptResult() { IsSucceeded = true }); }
public void Initialize(AddonInfomation info) { if (this._isInitialized) { return; } this._handler.Initialize(info.Name.Value, info.PackageID.Value); this._isInitialized = true; }
/// <summary> /// ローカルデータにセットする /// </summary> /// <param name="infomation"></param> /// <param name="addon"></param> private void SetLocalData(AddonInfomation infomation, Addon addon) { infomation.ID.Value = addon.Id; infomation.Name.Value = addon.Name; infomation.Author.Value = addon.Author; infomation.Description.Value = addon.Description; infomation.Version.Value = Version.Parse(addon.Version); infomation.Identifier.Value = addon.Identifier; infomation.Permissions.AddRange(addon.Permissions); infomation.TargetAPIVersion.Value = Version.Parse(addon.TargetAPIVersion); }
/// <summary> /// DBのデータにセットする /// </summary> /// <param name="infomation"></param> /// <param name="addon"></param> private void SetDBData(AddonInfomation infomation, Addon addon) { addon.Id = infomation.ID.Value; addon.Name = infomation.Name.Value; addon.Author = infomation.Author.Value; addon.Description = infomation.Description.Value; addon.Version = infomation.Version.Value.ToString(); addon.Identifier = infomation.Identifier.Value; addon.Permissions = infomation.Permissions; addon.PackageID = infomation.PackageID.Value; addon.TargetAPIVersion = infomation.TargetAPIVersion.Value.ToString(); }
public void Initialize(AddonInfomation infomation, IJavaScriptExecuter engine) { if (!infomation.HasPermission(PermissionNames.Output)) { this.output = null; } else { this.output !.SetInfo(infomation); } if (!infomation.HasPermission(PermissionNames.Hooks)) { this.hooks = null; } if (infomation.HasPermission(PermissionNames.Log)) { this.log !.Initialize(infomation); } else { this.log = null; } if (infomation.HasPermission(PermissionNames.Resource)) { this.resource !.Initialize(infomation); } else { this.resource = null; } if (infomation.HasPermission(PermissionNames.Storage)) { this.storage !.localStorage.Initialize(infomation); } else { this.storage = null; } if (infomation.HasPermission(PermissionNames.Tab)) { this.tab !.SetInfo(infomation); } else { this.tab = null; } }
public AddonInfomationViewModel(AddonInfomation info) { this.AddonInfomation = info; this.Name = info.Name.ToReadOnlyReactiveProperty(); this.Version = info.Version.Select(v => v.ToString()).ToReadOnlyReactiveProperty(); this.Author = info.Author.ToReadOnlyReactiveProperty(); this.Description = info.Description.ToReadOnlyReactiveProperty(); this.ID = info.ID.ToReadOnlyReactiveProperty(); this.UpdateCommand = new ReactiveCommand(); this.IconPath = info.IconPathRelative.ToReadOnlyReactiveProperty(); this.UninstallCommand = new AsyncReactiveCommand <int>(); }
public void Initialize(AddonInfomation addon) { var version = Assembly.GetExecutingAssembly().GetName().Version; this.client.DefaultRequestHeaders.Referrer = new Uri(Const::NetConstant.NiconicoBaseURL); this.client.DefaultRequestHeaders.UserAgent.ParseAdd($"Mozilla/5.0 (Niconicome/{version?.Major}.{version?.Minor}.{version?.Build})"); this.client.DefaultRequestHeaders.Add("X-Frontend-Id", "6"); this.client.DefaultRequestHeaders.Add("X-Frontend-Version", "0"); if (!addon.Permissions.Contains(PermissionNames.Session)) { this.NicoHttp = null; } }
/// <summary> /// アドオンを保存する /// </summary> /// <param name="addon"></param> /// <returns></returns> public IAttemptResult <int> StoreAddon(AddonInfomation addon) { if (string.IsNullOrEmpty(addon.Identifier.Value)) { if (this.IsInstallled(db => db.Name == addon.Name.Value)) { return(new AttemptResult <int>() { Message = $"{addon.Name.Value}は既にインストールされています。" }); } } else { //任意識別子が指定されている場合 if (this.IsInstallled(d => d.Identifier == addon.Identifier.Value)) { return(new AttemptResult <int>() { Message = $"{addon.Identifier.Value}は既にインストールされています。" }); } } var data = new Addon(); this.SetDBData(addon, data); IAttemptResult <int> result = this.dataBase.Store(data, Addon.TableName); if (!result.IsSucceeded) { if (result.Exception is not null) { this.logger.Error("アドオンの追加に失敗しました。", result.Exception); } else { this.logger.Error($"アドオンの追加に失敗しました。(詳細:{result.Message})"); } return(result); } return(new AttemptResult <int>() { IsSucceeded = true, Data = result.Data }); }
public string GetAddonInfomationString() { if (this.Infomation.Value is null) { return(string.Empty); } AddonInfomation info = this.Infomation.Value; var sb = new StringBuilder(); sb.AppendLine($"名前:{info.Name.Value}"); sb.AppendLine($"作者:{info.Author.Value}"); sb.AppendLine($"説明:{info.Description.Value}"); sb.AppendLine($"バージョン:{info.Version.Value}"); sb.AppendLine($"識別子:{info.Identifier.Value}"); if (info.Permissions.Count > 0) { sb.AppendLine("権限一覧 " + "-".Repeat(60)); foreach (var permission in info.Permissions) { Permission?data = this.permissionsHandler.GetPermission(permission); if (data is null) { continue; } sb.AppendLine($"権限名:{data.Name}"); sb.AppendLine($"説明:{data.Description}"); } } if (info.HostPermissions.Count > 0) { sb.AppendLine("ホスト権限一覧(アドオンが自由にデータを送受信できるURL)" + "-".Repeat(60)); sb.AppendLine("!注意!:悪意のあるアドオンは、これらのURLにあなたの情報を送信することができます。適用範囲が広すぎるもの(たとえば、「http://*/」など)はできるだけ許可しないでください。アプリケーションはこのような攻撃に対する防御機構を持ちません。"); foreach (var host in info.HostPermissions) { sb.AppendLine(host); } } return(sb.ToString()); }
public AddonInfomationViewModel(AddonInfomation info, IDialogService dialogService) { this.AddonInfomation = info; this.Name = info.Name.ToReadOnlyReactiveProperty(); this.Version = info.Version.Select(v => v.ToString()).ToReadOnlyReactiveProperty(); this.Author = info.Author.ToReadOnlyReactiveProperty(); this.Description = info.Description.ToReadOnlyReactiveProperty(); this.ID = info.ID.ToReadOnlyReactiveProperty(); this.IconPath = info.IconPathRelative.Select(p => Path.Combine(AppContext.BaseDirectory, FileFolder.AddonsFolder, info.PackageID.Value, p)).ToReadOnlyReactiveProperty(); this.service = dialogService; this.UpdateCommand = new ReactiveCommand() .WithSubscribe(() => { if (WS::AddonPage.InstallManager.IsInstalling.Value) { WS::AddonPage.Queue.Enqueue("ほかのアドオンをインストール中です。"); return; } WS::AddonPage.InstallManager.MarkAsUpdate(this.AddonInfomation); dialogService.Show(nameof(AddonInstallWindow)); }); this.UninstallCommand = new AsyncReactiveCommand <int>() .WithSubscribe(async id => { IDialogResult messageBoxResult = CommonMessageBoxAPI.Show(this.service !, "本当にアンインストールしますか?", CommonMessageBoxAPI.MessageType.Warinng, CommonMessageBoxButtons.Yes | CommonMessageBoxButtons.No | CommonMessageBoxButtons.Cancel); if (messageBoxResult.Result != ButtonResult.Yes) { return; } IAttemptResult result = await WS::AddonPage.InstallManager.UnistallAddonAsync(id); if (!result.IsSucceeded) { WS::AddonPage.Queue.Enqueue("アンインストールに失敗しました。"); } else { WS::AddonPage.Queue.Enqueue("アンインストールしました。"); } }); }
/// <summary> /// インストール済みで、実体のないアドオンをアンインストールする /// </summary> /// <returns></returns> private void UninstallIfAble(AddonInfomation addon) { var isIdNull = string.IsNullOrEmpty(addon.Identifier.Value); if (!this.storeHandler.IsInstallled(db => isIdNull ? db.Name == addon.Name.Value : db.Identifier == addon.Identifier.Value)) { return; } AddonInfomation?info = this.storeHandler.GetAddon(db => isIdNull ? db.Name == addon.Name.Value : db.Identifier == addon.Identifier.Value); if (info is null) { return; } else { this.uninstaller.Uninstall(info.ID.Value); } }
/// <summary> /// アドオンを更新する /// </summary> /// <param name="addon"></param> /// <returns></returns> public IAttemptResult <int> Update(AddonInfomation addon) { if (!this.IsInstallled(a => addon.Identifier.Value.IsNullOrEmpty() ? a.Id == addon.ID.Value : a.Identifier == addon.Identifier.Value)) { return(new AttemptResult <int>() { Message = "アドオンがインストールされていません。" }); } var db = new Addon(); this.SetDBData(addon, db); IAttemptResult result = this.dataBase.Update(db, Addon.TableName); if (!result.IsSucceeded) { if (result.Exception is not null) { this.logger.Error("アドオンの更新に失敗しました。", result.Exception); } else { this.logger.Error($"アドオンの更新に失敗しました。(詳細:{result.Message})"); } return(new AttemptResult <int>() { Message = result.Message, Exception = result.Exception }); } return(new AttemptResult <int>() { IsSucceeded = true, Data = addon.ID.Value }); }
/// <summary> /// アドオンを取得する /// </summary> /// <param name="predicate"></param> /// <returns></returns> public AddonInfomation?GetAddon(Expression <Func <Addon, bool> > predicate) { IAttemptResult <Addon> result = this.dataBase.GetRecord(Addon.TableName, predicate); if (!result.IsSucceeded || result.Data is null) { if (result.Exception is not null) { this.logger.Error("アドオンの取得に失敗しました。", result.Exception); return(null); } else { this.logger.Error($"アドオンの取得に失敗しました。(詳細:{result.Message})"); return(null); } } AddonInfomation infomation = this.container.GetAddon(result.Data.Id); this.SetLocalData(infomation, result.Data); return(infomation); }
public void MarkAsUpdate(AddonInfomation infomation) { this.updateInfo = infomation; }
public void Initialize(AddonInfomation info) { this.info = info; }
/// <summary> /// アドオンを初期化する /// </summary> /// <returns></returns> public async Task <IAttemptResult> InitializeAsync() { if (this.isInitialized) { return(new AttemptResult() { Message = "既に初期化されています。" }); } this._initializeAwaiterHandler.RegisterStep(AwaiterNames.Addon, typeof(VM::MainWindowViewModel)); await this._initializeAwaiterHandler.GetAwaiter(AwaiterNames.Addon); IAttemptResult dResult = this._uninstaller.DeleteListed(); if (!dResult.IsSucceeded) { return(new AttemptResult() { Message = "アンインストール済みアドオンフォルダーの削除に失敗しました。", Exception = dResult.Exception }); } IAttemptResult mResult = this._installer.ReplaceTemporaryFiles(); if (!mResult.IsSucceeded) { return(new AttemptResult() { Message = mResult.Message, Exception = mResult.Exception }); } List <string> packages; try { packages = this._directoryIO.GetDirectorys(FileFolder.AddonsFolder); } catch (Exception e) { this._logger.Error("アドオンパッケージ一覧の取得に失敗しました。", e); return(new AttemptResult() { Message = "アドオンパッケージ一覧の取得に失敗しました。", Exception = e }); } bool isDevMode = this._settingHandler.GetBoolSetting(SettingsEnum.IsDevMode); bool isAddonDebuggingEnable = this._settingHandler.GetBoolSetting(SettingsEnum.IsAddonDebugEnable); foreach (var packagePath in packages) { string package = Path.GetFileName(packagePath); IAttemptResult <bool> result = await this._engine.InitializeAsync(package, isDevMode); if (!result.IsSucceeded) { var failedResult = new FailedAddonResult(package, result.Message ?? string.Empty, result.Data); this.LoadFailedAddons.Add(failedResult); } } foreach (KeyValuePair <int, IAddonContext> item in this._contexts.Contexts) { AddonInfomation info = this._container.GetAddon(item.Key); IAPIEntryPoint entryPoint = DIFactory.Provider.GetRequiredService <IAPIEntryPoint>(); IAttemptResult result = item.Value.Initialize(info, engine => { entryPoint.Initialize(info, engine); engine.AddHostObject("application", entryPoint); IFetch fetch = DIFactory.Provider.GetRequiredService <IFetch>(); fetch.Initialize(info); Func <string, dynamic?, Task <Response> > fetchFunc = (url, optionObj) => { var option = new FetchOption() { method = optionObj?.method, body = optionObj?.body, credentials = optionObj?.credentials, }; return(fetch.FetchAsync(url, option)); }; engine.AddHostObject("fetch", fetchFunc); }, entryPoint, isAddonDebuggingEnable); if (!result.IsSucceeded) { var failedResult = new FailedAddonResult(info.PackageID.Value, result.Message ?? string.Empty, true); this.LoadFailedAddons.Add(failedResult); } } IAttemptResult <IEnumerable <string> > packageIds = this._storeHandler.GetAllAddonsPackageID(); if (packageIds.IsSucceeded && packageIds.Data is not null) { List <string> loaded = this._contexts.Contexts.Select(v => v.Value.AddonInfomation !.PackageID.Value).ToList(); foreach (var package in packageIds.Data) { if (!loaded.Contains(package)) { var failedResult = new FailedAddonResult(package, "インストールされていますが、ファイルが見つかりませんでした。", true); this.LoadFailedAddons.Add(failedResult); } } } this.isInitialized = true; return(new AttemptResult() { IsSucceeded = true }); }
public void SetInfo(AddonInfomation infomation) { this._addonInfomation = infomation; }
public void Initialize(AddonInfomation info) { this.http.Initialize(info); this.permissionsHandler.Initialize(info.HostPermissions); this.isInitialized = true; }
public void Initialize(AddonInfomation info) { this._handler.Initialize(info.PackageID.Value, info.Name.Value); }
/// <summary> /// アドオンの安全性を検証する /// </summary> /// <param name="dbData"></param> /// <param name="manifestData"></param> /// <returns></returns> private IAttemptResult CheckSafety(AddonInfomation dbData, AddonInfomation manifestData) { ///権限確認 if (manifestData.Permissions.Count != dbData.Permissions.Count) { this.logger.Error($"権限の不正な書き換えを検知しました。({dbData.Name.Value},{dbData.Permissions.Count}=>{manifestData.Permissions.Count})"); return(new AttemptResult() { Message = "権限が不正に書き換えられました。" }); } else { foreach (var permission in manifestData.Permissions) { if (!dbData.Permissions.Contains(permission)) { this.logger.Error($"権限の不正な書き換えを検知しました。({dbData.Name.Value},{permission})"); return(new AttemptResult() { Message = $"権限が不正に書き換えられました。{permission}" }); } } } if (manifestData.HostPermissions.Count != dbData.HostPermissions.Count) { this.logger.Error($"ホスト権限の不正な書き換えを検知しました。({dbData.Name.Value},{dbData.HostPermissions.Count}=>{manifestData.HostPermissions.Count})"); return(new AttemptResult() { Message = "ホスト権限が不正に書き換えられました。" }); } else { foreach (var permission in manifestData.HostPermissions) { if (!dbData.HostPermissions.Contains(permission)) { this.logger.Error($"ホスト権限の不正な書き換えを検知しました。({dbData.Name.Value},{permission})"); return(new AttemptResult() { Message = $"ホスト権限が不正に書き換えられました。{permission}" }); } } } //バージョン確認 if (manifestData.Version.Value.CompareTo(dbData.Version.Value) != 0) { this.logger.Error($"バージョンが不正に書き換えられました。({dbData.Version.Value}=>{manifestData.Version.Value})"); return(new AttemptResult() { Message = $"バージョンが不正に書き換えられました。({dbData.Version.Value}=>{manifestData.Version.Value})" }); } //APIバージョン確認 Version apiVersioin = Const::AddonConstant.APIVersion; if (manifestData.TargetAPIVersion.Value.CompareTo(apiVersioin) > 0) { this.logger.Error($"現在の実行環境はターゲットAPIバージョンを満たしていません。(current:{apiVersioin} target:{manifestData.TargetAPIVersion.Value})"); return(new AttemptResult() { Message = $"現在の実行環境はターゲットAPIバージョンを満たしていません。(current:{apiVersioin} target:{manifestData.TargetAPIVersion.Value})" }); } return(new AttemptResult() { IsSucceeded = true }); }