unit bs1PolicyUnit; interface uses System.SysUtils, System.Classes, System.Generics.Collections, System.SyncObjs, System.JSON, System.IOUtils, Winapi.Windows, Winapi.Messages, Winapi.ActiveX, Bs1FltCtrl; type // [1] MTP/Bluetooth ¼³Á¤ ±¸Á¶Ã¼ TMtpBtConfig = record Policy: Integer; FileSize: Integer; end; // [2] ÇÁ·Î¼¼½º ÈÅ ¼³Á¤ Ŭ·¡½º THookProcessItem = class public ProcessName: string; // Key (¿¹: FSQUIRT) DeviceType: TStringList; Mode: Integer; ExceptionPath: TStringList; Extension: TStringList; ExceptionExt: TStringList; // JSON Ű: exceptionExtenstion (¿ÀŸ ÁÖÀÇ) constructor Create(AName: string); destructor Destroy; override; function Clone: THookProcessItem; end; // [3] DataFlow Àüü ¼³Á¤ Ŭ·¡½º TDataFlowConfig = class public Seq: DWORD; // ±âº»°ª "1" GlobalExceptionPath: TStringList; // °øÅë ¿¹¿Ü °æ·Î // DeviceControl (MTP, BT) MtpConfig: TMtpBtConfig; BtConfig: TMtpBtConfig; CDROMConfig: TMtpBtConfig; UsbToUsbConfig: TMtpBtConfig; // HookProcess HookProcesses: TObjectList; constructor Create; destructor Destroy; override; procedure Assign(Source: TDataFlowConfig); // µ¥ÀÌÅÍ º¹»ç (UI Ãë¼Ò ±â´É Áö¿ø¿ë) end; TMatchCriteria = class public PropType: DWORD; MatchData: string; Enumerator: string; constructor Create(APropType: DWORD; AMatchData, AEnum: string); function Clone: TMatchCriteria; end; TPolicyItem = class public name: string; flag_: DWORD; // KCD_xxx °ª state_: TDeviceState; // Çã¿ë/Â÷´Ü/·Î±× isLog_: Boolean; targetGUID_: string; // pGUID matchPropType_: DWORD; // ¿¹: SPDRP_SERVICE, SPDRP_CLASSGUID // Ư¼ö ÀåÄ¡ Ç÷¡±× isBluetooth_: Boolean; Matches_: TObjectList; constructor Create(const AName: string; AFlag: DWORD; AGUIDStr: string; IsBT: Boolean = False); destructor Destroy; procedure AddMatch(PropType: DWORD; MatchData, Enumerator: string); function Clone: TPolicyItem; end; TBs1Policy = class private FPolicyFilePath: string; FLock: TCriticalSection; FPolicies: TObjectList; //FExceptionList: TStringList; FDataFlowSeq: string; FDataFlowConfig: TDataFlowConfig; // DataFlow ¼³Á¤ °´Ã¼ FUsbExceptList_: TStringList; FUsbExceptListLock_: TCriticalSection; public constructor Create; destructor Destroy; override; // °³º° Á¤Ã¥ »óÅ º¯°æ (UI ¿¬µ¿¿ë) //procedure UpdatePolicyStateInList(const GuidStr: string; NewState: TPolicyState); function CreatePolicy(const Name: string; Flag: TDeviceType; AGUID: string = ''; IsBT: Boolean = False): TPolicyItem; // procedure AddPolicy(Flag: DWORD; PropType: DWORD; const MatchData: string; pGUID: string; EnumStr: string; IsBT: Boolean = False); procedure AddPolicyObject(APolicy: TPolicyItem); procedure UpdatePolicyState(Flag: DWORD; NewState: TDeviceState; NewLogState: Boolean); procedure CopyPoliciesTo(ATargetList: TObjectList); function GetPolicyJsonArray: TJSONArray; // ÆÄÀÏ ÀÔÃâ·Â (JSON) procedure SavePolicyToFile; procedure LoadDataControlConfig; procedure LoadDataFlowConfig; procedure SaveDataFlowConfig; // DataFlow ¼³Á¤ Àü¿ë ÀúÀå ÇÔ¼ö property Policies: TObjectList read FPolicies; property DataFlowConfig: TDataFlowConfig read FDataFlowConfig; //property ExceptionList: TStringList read FExceptionList; procedure SaveDeviceControlExceptProcessConfig(ExceptionPath: TStrings); procedure LoadDeviceControlExceptProcessConfig(ExceptionPath: TStrings); function ParseStringArray(AJSONValue: TJSONValue): TArray; function IsUsbPortExcept(const DeviceInstancePath: string): Boolean; function RemoveUsbPortExcept(const Vendor, Product, Serial: string): Boolean; function AddUsbPortExcept(const Vendor, Product, Serial: string): Boolean; end; var gBs1Policy: TBs1Policy = nil; implementation { THookProcessItem } constructor THookProcessItem.Create(AName: string); begin ProcessName := AName; ExceptionPath := TStringList.Create; Extension := TStringList.Create; ExceptionExt := TStringList.Create; DeviceType:= TStringList.Create; Mode := 0; end; destructor THookProcessItem.Destroy; begin ExceptionPath.Free; Extension.Free; ExceptionExt.Free; DeviceType.Free; inherited; end; function THookProcessItem.Clone: THookProcessItem; begin Result := THookProcessItem.Create(Self.ProcessName); Result.DeviceType.Assign(Self.DeviceType); Result.Mode := Self.Mode; Result.ExceptionPath.Assign(Self.ExceptionPath); Result.Extension.Assign(Self.Extension); Result.ExceptionExt.Assign(Self.ExceptionExt); end; { TDataFlowConfig } constructor TDataFlowConfig.Create; begin Seq := 1; GlobalExceptionPath := TStringList.Create; HookProcesses := TObjectList.Create; // ±âº»°ª MtpConfig.Policy := 1; MtpConfig.FileSize := 20; BtConfig.Policy := 0; BtConfig.FileSize := 20; end; destructor TDataFlowConfig.Destroy; begin GlobalExceptionPath.Free; HookProcesses.Free; inherited; end; procedure TDataFlowConfig.Assign(Source: TDataFlowConfig); begin Self.Seq := Source.Seq; Self.GlobalExceptionPath.Assign(Source.GlobalExceptionPath); Self.MtpConfig := Source.MtpConfig; Self.BtConfig := Source.BtConfig; Self.CDROMConfig := Source.CDROMConfig; Self.UsbToUsbConfig := Source.UsbToUsbConfig; Self.HookProcesses.Clear; for var Item in Source.HookProcesses do Self.HookProcesses.Add(Item.Clone); end; { TMatchCriteria } constructor TMatchCriteria.Create(APropType: DWORD; AMatchData, AEnum: string); begin PropType := APropType; MatchData := AMatchData; Enumerator := AEnum; end; function TMatchCriteria.Clone: TMatchCriteria; begin Result := TMatchCriteria.Create(self.PropType, self.MatchData, self.Enumerator); end; { TPolicyItem } constructor TPolicyItem.Create(const AName: string; AFlag: DWORD; AGUIDStr: string; IsBT: Boolean); begin Name := AName; flag_ := AFlag; targetGUID_ := AGUIDStr; isBluetooth_ := IsBT; state_ := dsEnable; // ±âº»°ª isLog_:= False; matches_ := TObjectList.Create; end; destructor TPolicyItem.Destroy; begin Matches_.Free; inherited; end; procedure TPolicyItem.AddMatch(PropType: DWORD; MatchData, Enumerator: string); begin Matches_.Add(TMatchCriteria.Create(PropType, MatchData, Enumerator)); end; function TPolicyItem.Clone: TPolicyItem; var Match: TMatchCriteria; begin // ±âº» ÇÊµå º¹»ç Result := TPolicyItem.Create(self.name, self.flag_, self.targetGUID_, self.isBluetooth_); Result.state_ := self.state_; Result.isLog_ := self.isLog_; Result.matchPropType_ := self.matchPropType_; // Match ¸®½ºÆ® ³»ºÎ ¾ÆÀÌÅ۵鵵 ±íÀº º¹»ç ¼öÇà for Match in self.Matches_ do begin Result.Matches_.Add(Match.Clone); end; end; { procedure TDeviceGuardEngine.AddDefaultPolicy(const Name, GuidStr: string; IsBT: Boolean); begin FLock.Enter; try // Áߺ¹ È®ÀÎ ÈÄ ¾øÀ¸¸é Ãß°¡ for var Item in FPolicies do if IsEqualGUID(Item.GUID, StringToGUID(GuidStr)) then Exit; FPolicies.Add(TPolicyItem.Create(Name, GuidStr, psLog, IsBT)); finally FLock.Leave; end; end; procedure TDeviceGuardEngine.UpdatePolicyStateInList(const GuidStr: string; NewState: TPolicyState); var TargetGUID: TGUID; begin TargetGUID := StringToGUID(GuidStr); FLock.Enter; try for var Item in FPolicies do begin if IsEqualGUID(Item.GUID, TargetGUID) then begin Item.State := NewState; Break; end; end; finally FLock.Leave; end; end; } { procedure TDeviceGuardEngine.AddPolicy(Flag: DWORD; PropType: DWORD; const MatchData: string; pGUID: string; EnumStr: string; IsBT: Boolean); begin FLock.Enter; try // Flag Áߺ¹ üũ for var Item in FPolicies do if Item.flag_ = Flag then Exit; FPolicies.Add(TPolicyItem.Create(Flag, PropType, MatchData, pGUID, EnumStr, IsBT)); finally FLock.Leave; end; end; } //////////////////////////////////////////////////////////////// // ÇïÆÛ: JSON ¹è¿­ -> ½ºÆ®¸µ¸®½ºÆ® procedure JsonArrayToStrings(JArr: TJSONArray; List: TStrings); begin List.Clear; if JArr = nil then Exit; for var I := 0 to JArr.Count - 1 do List.Add(JArr.Items[I].Value); end; // ÇïÆÛ: ½ºÆ®¸µ¸®½ºÆ® -> JSON ¹è¿­ function StringsToJsonArray(List: TStrings): TJSONArray; begin Result := TJSONArray.Create; for var S in List do Result.Add(S); end; { TBs1Policy } constructor TBs1Policy.Create; begin gBs1Policy:= self; FPolicies := TObjectList.Create; FLock := TCriticalSection.Create; FDataFlowConfig := TDataFlowConfig.Create; FPolicyFilePath := ChangeFileExt(ParamStr(0), '.json'); // //FExceptionList := TStringList.Create; FDataFlowSeq := '1'; // ±âº»°ª FUsbExceptList_ := TStringList.Create; FUsbExceptListLock_ := TCriticalSection.Create; end; destructor TBs1Policy.Destroy; begin FUsbExceptList_.Free; FUsbExceptListLock_.Free; FDataFlowConfig.Free; // FExceptionList.Free; FPolicies.Free; FLock.Free; inherited; end; function TBs1Policy.AddUsbPortExcept(const Vendor, Product, Serial: string): Boolean; var Key: string; begin Key := Format('USB\VID_%s&PID_%s\%s', [Vendor, Product, Serial]); Key := Trim(Key); //OutputDebugStringW(PChar(Format('bs1 (key : %s)', [Key]))); FUsbExceptListLock_.Enter; try // Sorted=True, Duplicates=dupIgnore ¼³Á¤ ´öºÐ¿¡ Add¸¸ È£ÃâÇØµµ Áߺ¹Ã¼Å© µÊ FUsbExceptList_.Add(Key); Result := True; finally FUsbExceptListLock_.Leave; end; end; function TBs1Policy.RemoveUsbPortExcept(const Vendor, Product, Serial: string): Boolean; var Key: string; Idx: Integer; begin Result:= False; Key := Format('USB\VID_%s&PID_%s\%s', [Vendor, Product, Serial]); Key := Trim(Key); //OutputDebugStringW(PChar(Format('bs1 (key : %s)', [Key]))); FUsbExceptListLock_.Enter; try Idx := FUsbExceptList_.IndexOf(Key); if Idx >= 0 then begin FUsbExceptList_.Delete(Idx); Result := True; end; finally FUsbExceptListLock_.Leave; end; end; function TBs1Policy.IsUsbPortExcept(const DeviceInstancePath: string): Boolean; begin FUsbExceptListLock_.Enter; try // IndexOf´Â ´ë¼Ò¹®ÀÚ ¹«½Ã(CaseSensitive=False)ÇÏ¿© ãÀ½ Result := FUsbExceptList_.IndexOf(DeviceInstancePath) >= 0; finally FUsbExceptListLock_.Leave; end; end; procedure TBs1Policy.CopyPoliciesTo(ATargetList: TObjectList); begin if ATargetList = nil then Exit; FLock.Enter; try ATargetList.Clear; // ´ë»ó ¸®½ºÆ® ÃʱâÈ­ (Çʿ信 µû¶ó ÁÖ¼® ó¸® °¡´É) for var Item in FPolicies do begin // °¢ ¾ÆÀÌÅÛÀ» º¹Á¦(Clone)ÇÏ¿© ´ë»ó ¸®½ºÆ®¿¡ Ãß°¡ // TObjectList°¡ OwnsObjects=True¶ó¸é ³ªÁß¿¡ ATargetList°¡ ÇØÁ¦µÉ ¶§ º¹Á¦µÈ °´Ã¼µéµµ ÀÚµ¿ ÇØÁ¦µÊ ATargetList.Add(Item.Clone); end; finally FLock.Leave; end; end; function TBs1Policy.ParseStringArray(AJSONValue: TJSONValue): TArray; var LArray: TJSONArray; LString: TJSONString; I: Integer; begin Result := []; if AJSONValue = nil then Exit; if AJSONValue is TJSONArray then begin LArray := AJSONValue as TJSONArray; SetLength(Result, LArray.Count); for I := 0 to LArray.Count - 1 do Result[I] := LArray.Items[I].Value; end else if (AJSONValue is TJSONString) then begin LString := AJSONValue as TJSONString; if not LString.Value.IsEmpty then Result := LString.Value.Split(['|']); end; end; function TBs1Policy.CreatePolicy(const Name: string; Flag: TDeviceType; AGUID: string; IsBT: Boolean): TPolicyItem; begin Result := TPolicyItem.Create(Name, DWORD(Flag), AGUID, IsBT); end; procedure TBs1Policy.AddPolicyObject(APolicy: TPolicyItem); begin FLock.Enter; try // Áߺ¹ üũ (Flag ±âÁØ) for var Item in FPolicies do begin if Item.flag_ = APolicy.flag_ then begin APolicy.Free; // ÀÌ¹Ì ÀÖÀ¸¸é ÇØÁ¦ÇÏ°í ¹«½Ã Exit; end; end; FPolicies.Add(APolicy); finally FLock.Leave; end; end; function TBs1Policy.GetPolicyJsonArray: TJSONArray; var JObjPolicy, JObjMatch: TJSONObject; JArrMatch: TJSONArray; begin Result := TJSONArray.Create; try for var Item in FPolicies do begin JObjPolicy := TJSONObject.Create; JObjPolicy.AddPair('name', Item.Name); JObjPolicy.AddPair('flag', TJSONNumber.Create(Item.flag_)); JObjPolicy.AddPair('state', TJSONNumber.Create(Ord(Item.state_))); // booleanÀ» int·Î ÀúÀå (±âÁ¸ ·ÎÁ÷ À¯Áö) if Item.isLog_ then JObjPolicy.AddPair('log', TJSONNumber.Create(1)) else JObjPolicy.AddPair('log', TJSONNumber.Create(0)); if Item.targetGUID_ <> '' then JObjPolicy.AddPair('guid', Item.targetGUID_); // Match ¹è¿­ »ý¼º if Item.matches_.Count > 0 then begin JArrMatch := TJSONArray.Create; for var Match in Item.matches_ do begin JObjMatch := TJSONObject.Create; JObjMatch.AddPair('propType', TJSONNumber.Create(Match.PropType)); JObjMatch.AddPair('matchData', Match.MatchData); JObjMatch.AddPair('enumerator', Match.Enumerator); JArrMatch.AddElement(JObjMatch); end; JObjPolicy.AddPair('match', JArrMatch); end; Result.AddElement(JObjPolicy); end; except Result.Free; raise; end; end; procedure TBs1Policy.UpdatePolicyState(Flag: DWORD; NewState: TDeviceState; NewLogState: Boolean); begin FLock.Enter; try for var Item in FPolicies do begin if Item.flag_ = Flag then begin Item.state_ := NewState; Item.isLog_ := NewLogState; Break; end; end; finally FLock.Leave; end; end; // --------------------------------------------------------------------------- // [Save] bs1dc.json ÆÄÀÏÀ» Àо deviceControl ºÎºÐ¸¸ ¾÷µ¥ÀÌÆ® ÈÄ ÀúÀå // --------------------------------------------------------------------------- procedure TBs1Policy.SavePolicyToFile; var JsonText: string; JRootVal: TJSONValue; JObjRoot, JObjDataFlow: TJSONObject; JArrPolicies: TJSONArray; IsNewFile: Boolean; begin FLock.Enter; try IsNewFile := not FileExists(FPolicyFilePath); JObjRoot := nil; // 1. ±âÁ¸ ÆÄÀÏÀÌ ÀÖÀ¸¸é Àо ÆÄ½Ì, ¾øÀ¸¸é »õ·Î »ý¼º if not IsNewFile then begin JsonText := TFile.ReadAllText(FPolicyFilePath); JRootVal := TJSONObject.ParseJSONValue(JsonText); if JRootVal is TJSONObject then JObjRoot := JRootVal as TJSONObject else JRootVal.Free; // À߸øµÈ Æ÷¸ËÀÌ¸é Æó±â end; if JObjRoot = nil then begin JObjRoot := TJSONObject.Create; JObjRoot.AddPair('dataFlowSeq', TJSONNumber.Create(1)); end; try // // 2. 'dataFlow' °´Ã¼ ã±â ¶Ç´Â »ý¼º // if not JObjRoot.TryGetValue('dataFlow', JObjDataFlow) then // begin // JObjDataFlow := TJSONObject.Create; // JObjRoot.AddPair('dataFlow', JObjDataFlow); // end; // 3. ±âÁ¸ÀÇ 'deviceControl' ۰¡ ÀÖ´Ù¸é Á¦°Å (»õ·Î µ¤¾î¾²±â À§ÇØ) if JObjRoot.GetValue('deviceControl') <> nil then begin JObjRoot.RemovePair('deviceControl').Free; end; // 4. ÇöÀç Á¤Ã¥µéÀ» JSON Array·Î º¯È¯ÇÏ¿© Ãß°¡ JArrPolicies := GetPolicyJsonArray; JObjRoot.AddPair('deviceControl', JArrPolicies); // 5. ÆÄÀÏ ÀúÀå // (FormatÀ» ÇÏ¸é º¸±â ÁÁÁö¸¸, ¿ë·®ÀÌ Ä¿Áú ¼ö ÀÖ½À´Ï´Ù. ÇÊ¿ä ½Ã TJsonFormatType.Indented »ç¿ë) TFile.WriteAllText(FPolicyFilePath, JObjRoot.ToString); finally JObjRoot.Free; // Root¸¦ ÇØÁ¦Çϸé ÇÏÀ§ °´Ã¼µéµµ ¸ðµÎ ÇØÁ¦µÊ end; finally FLock.Leave; end; end; // --------------------------------------------------------------------------- // [Load 1] bs1dc.jsonÀÇ dataFlow -> deviceControl (±âÁ¸ bs1dc ¿ªÇÒ) ·Îµå // --------------------------------------------------------------------------- procedure TBs1Policy.LoadDataControlConfig; var JsonText: string; JRootVal: TJSONValue; JArrPolicies, JArrMatch: TJSONArray; JObjRoot, JObjPolicy, JObjMatch: TJSONObject; FlagVal, StateVal, LogVal, PropVal: Integer; NameStr, GuidStr, MatchDataStr, EnumStr: string; NewPolicy: TPolicyItem; begin if not FileExists(FPolicyFilePath) then Exit; FLock.Enter; try FPolicies.Clear; // ±âÁ¸ Á¤Ã¥ ÃʱâÈ­ JsonText := TFile.ReadAllText(FPolicyFilePath); JRootVal := TJSONObject.ParseJSONValue(JsonText); try // ·çÆ® È®ÀÎ if (JRootVal is TJSONObject) then begin JObjRoot := JRootVal as TJSONObject; // [¼öÁ¤] ÃÖ»óÀ§ °æ·Î¿¡¼­ 'deviceControl' ã±â // ±¸Á¶: { "dataFlow": {...}, "deviceControl": [...] } if JObjRoot.TryGetValue('deviceControl', JArrPolicies) then begin for var I := 0 to JArrPolicies.Count - 1 do begin JObjPolicy := JArrPolicies.Items[I] as TJSONObject; if JObjPolicy.TryGetValue('name', NameStr) and JObjPolicy.TryGetValue('flag', FlagVal) and JObjPolicy.TryGetValue('state', StateVal) then begin GuidStr := ''; JObjPolicy.TryGetValue('guid', GuidStr); LogVal := 0; JObjPolicy.TryGetValue('log', LogVal); // Á¤Ã¥ °´Ã¼ »ý¼º var IsBT := (DWORD(FlagVal) = DWORD(BDC_BLUETOOTH)); NewPolicy := TPolicyItem.Create(NameStr, DWORD(FlagVal), GuidStr, IsBT); NewPolicy.state_ := TDeviceState(StateVal); NewPolicy.isLog_ := (LogVal <> 0); // match ¹è¿­ ·Îµå if JObjPolicy.TryGetValue('match', JArrMatch) then begin for var K := 0 to JArrMatch.Count - 1 do begin JObjMatch := JArrMatch.Items[K] as TJSONObject; if JObjMatch.TryGetValue('propType', PropVal) and JObjMatch.TryGetValue('matchData', MatchDataStr) and JObjMatch.TryGetValue('enumerator', EnumStr) then begin NewPolicy.AddMatch(DWORD(PropVal), MatchDataStr, EnumStr); end; end; end; FPolicies.Add(NewPolicy); end; end; end; end; finally JRootVal.Free; end; finally FLock.Leave; end; end; procedure TBs1Policy.LoadDataFlowConfig; var JsonText: string; JRoot, JDataFlow, JRule, JDevCtrl, JHookProc, JItem: TJSONObject; JArr: TJSONArray; JVal: TJSONValue; SeqKey: string; HookItem: THookProcessItem; SeqInt: Integer; JArrDevice: TJSONArray; StrDevice: string; begin if not FileExists(FPolicyFilePath) then Exit; FLock.Enter; try JsonText := TFile.ReadAllText(FPolicyFilePath); // ParseJSONValue´Â ½ÇÆÐ ½Ã nil ¹ÝȯÇϹǷΠüũ Çʼö JRoot := TJSONObject.ParseJSONValue(JsonText) as TJSONObject; try if JRoot = nil then Exit; // 0. dataFlowSeq °ª Àбâ if JRoot.TryGetValue('dataFlowSeq', SeqInt) then FDataFlowConfig.Seq := SeqInt; // 1. dataFlow °´Ã¼ ã±â if not JRoot.TryGetValue('dataFlow', JDataFlow) then Exit; // 2. Seq Ű (¿¹: "6") ã±â SeqKey := FDataFlowConfig.Seq.ToString; if not JDataFlow.TryGetValue(SeqKey, JRule) then Exit; // 3. Exception Path (Global) if JRule.TryGetValue('exceptionPath', JArr) then JsonArrayToStrings(JArr, FDataFlowConfig.GlobalExceptionPath); // 4. deviceControl ·Îµå (±âÁ¸ ÄÚµå À¯Áö) if JRule.TryGetValue('deviceControl', JDevCtrl) then begin if JDevCtrl.TryGetValue('mtp', JItem) then begin JItem.TryGetValue('policy', FDataFlowConfig.MtpConfig.Policy); JItem.TryGetValue('fileSize', FDataFlowConfig.MtpConfig.FileSize); end; if JDevCtrl.TryGetValue('bluetooth', JItem) then begin JItem.TryGetValue('policy', FDataFlowConfig.BtConfig.Policy); JItem.TryGetValue('fileSize', FDataFlowConfig.BtConfig.FileSize); end; if JDevCtrl.TryGetValue('cdrom', JItem) then begin JItem.TryGetValue('policy', FDataFlowConfig.CDROMConfig.Policy); JItem.TryGetValue('fileSize', FDataFlowConfig.CDROMConfig.FileSize); end; if JDevCtrl.TryGetValue('usbTousb', JItem) then begin JItem.TryGetValue('policy', FDataFlowConfig.UsbToUsbConfig.Policy); JItem.TryGetValue('fileSize', FDataFlowConfig.UsbToUsbConfig.FileSize); end; end; // 5. hookProcess ·Îµå FDataFlowConfig.HookProcesses.Clear; if JRule.TryGetValue('hookProcess', JHookProc) then begin for var Pair in JHookProc do begin JItem := Pair.JsonValue as TJSONObject; HookItem := THookProcessItem.Create(Pair.JsonString.Value); // Key = ProcessName // [°ËÅä] deviceType ·Îµå ·ÎÁ÷ HookItem.DeviceType.Clear; JVal := JItem.GetValue('deviceType'); if JVal <> nil then begin if JVal is TJSONArray then begin // ¹è¿­ÀÎ °æ¿ì (["mtp", "cdrom"]) JsonArrayToStrings(JVal as TJSONArray, HookItem.DeviceType); end else if JVal is TJSONString then begin // ¹®ÀÚ¿­ÀÎ °æ¿ì ("bluetooth") if (JVal as TJSONString).Value.Trim <> '' then HookItem.DeviceType.Add((JVal as TJSONString).Value); end; end; JItem.TryGetValue('mode', HookItem.Mode); if JItem.TryGetValue('exceptionPath', JArr) then JsonArrayToStrings(JArr, HookItem.ExceptionPath); if JItem.TryGetValue('extension', JArr) then JsonArrayToStrings(JArr, HookItem.Extension); if JItem.TryGetValue('exceptionExtenstion', JArr) then JsonArrayToStrings(JArr, HookItem.ExceptionExt); FDataFlowConfig.HookProcesses.Add(HookItem); end; end; finally JRoot.Free; end; finally FLock.Leave; end; end; procedure TBs1Policy.SaveDataFlowConfig; var JsonText: string; JRoot, JDataFlow, JRule, JDevCtrl, JHookProc, JHookItem, JSubItem: TJSONObject; JArrDeviceType: TJSONArray; JSeqValue: TJSONValue; CurrentSeq, NewSeq: Integer; OldSeqStr, NewSeqStr: string; begin FLock.Enter; try // 1. ±âÁ¸ ÆÄÀÏ ·Îµå (ÁÖ¼® º¸Á¸ ¹× ±¸Á¶ À¯Áö À§ÇØ) JRoot := nil; if FileExists(FPolicyFilePath) then begin try JsonText := TFile.ReadAllText(FPolicyFilePath); JRoot := TJSONObject.ParseJSONValue(JsonText) as TJSONObject; except JRoot := nil; end; end; if JRoot = nil then JRoot := TJSONObject.Create; try // 2. Seq °ü¸® (Áõ°¡ ·ÎÁ÷) CurrentSeq := 0; if JRoot.TryGetValue('dataFlowSeq', CurrentSeq) then begin // ¼º°øÀûÀ¸·Î ÀÐÀ½ end; // [ÁÖÀÇ] ¸¸¾à ´Ü¼øÈ÷ ÇöÀç ¼³Á¤À» ÀúÀåÇÏ´Â °ÍÀ̶ó¸é Seq¸¦ Áõ°¡½ÃŰÁö ¾Ê¾Æµµ µÉ ¼ö ÀÖ½À´Ï´Ù. // ¿©±â¼­´Â ¿äûÇϽŠ·ÎÁ÷´ë·Î +1 Áõ°¡½Ãŵ´Ï´Ù. NewSeq := CurrentSeq + 1; FDataFlowConfig.Seq := NewSeq; OldSeqStr := CurrentSeq.ToString; NewSeqStr := NewSeq.ToString; // RootÀÇ Seq ¾÷µ¥ÀÌÆ® if JRoot.GetValue('dataFlowSeq') <> nil then JRoot.RemovePair('dataFlowSeq').Free; JRoot.AddPair('dataFlowSeq', TJSONNumber.Create(NewSeq)); // 3. dataFlow °´Ã¼ È®º¸ JDataFlow := nil; if JRoot.GetValue('dataFlow') <> nil then JDataFlow := JRoot.GetValue('dataFlow') as TJSONObject; if JDataFlow = nil then begin JDataFlow := TJSONObject.Create; JRoot.AddPair('dataFlow', JDataFlow); end; // ±âÁ¸ Seq µ¥ÀÌÅÍ »èÁ¦ (·Ñ¸µ ¾÷µ¥ÀÌÆ®) if JDataFlow.GetValue(OldSeqStr) <> nil then JDataFlow.RemovePair(OldSeqStr).Free; // Ȥ½Ã ¸ð¸¦ Ãæµ¹ ¹æÁö if JDataFlow.GetValue(NewSeqStr) <> nil then JDataFlow.RemovePair(NewSeqStr).Free; // 4. »õ ±ÔÄ¢ »ý¼º (NewSeq) JRule := TJSONObject.Create; JDataFlow.AddPair(NewSeqStr, JRule); // ExceptionPath JRule.AddPair('exceptionPath', StringsToJsonArray(FDataFlowConfig.GlobalExceptionPath)); // DeviceControl JDevCtrl := TJSONObject.Create; // MTP JSubItem := TJSONObject.Create; JSubItem.AddPair('policy', TJSONNumber.Create(FDataFlowConfig.MtpConfig.Policy)); JSubItem.AddPair('fileSize', TJSONNumber.Create(FDataFlowConfig.MtpConfig.FileSize)); JDevCtrl.AddPair('mtp', JSubItem); // Bluetooth JSubItem := TJSONObject.Create; JSubItem.AddPair('policy', TJSONNumber.Create(FDataFlowConfig.BtConfig.Policy)); JSubItem.AddPair('fileSize', TJSONNumber.Create(FDataFlowConfig.BtConfig.FileSize)); JDevCtrl.AddPair('bluetooth', JSubItem); // CDROM JSubItem := TJSONObject.Create; JSubItem.AddPair('policy', TJSONNumber.Create(FDataFlowConfig.CDROMConfig.Policy)); JSubItem.AddPair('fileSize', TJSONNumber.Create(FDataFlowConfig.CDROMConfig.FileSize)); JDevCtrl.AddPair('cdrom', JSubItem); // UsbToUsb JSubItem := TJSONObject.Create; JSubItem.AddPair('policy', TJSONNumber.Create(FDataFlowConfig.UsbToUsbConfig.Policy)); JSubItem.AddPair('fileSize', TJSONNumber.Create(FDataFlowConfig.UsbToUsbConfig.FileSize)); JDevCtrl.AddPair('usbTousb', JSubItem); JRule.AddPair('deviceControl', JDevCtrl); // 5. HookProcess ÀúÀå (¿©±â°¡ ÇÙ½É) JHookProc := TJSONObject.Create; for var Item in FDataFlowConfig.HookProcesses do begin JHookItem := TJSONObject.Create; // [ÇÙ½É ¼öÁ¤] deviceType ÀúÀå ·ÎÁ÷ °³¼± // 1°³¸é String, ±× ¿Ü¿£ Array·Î ÀúÀåÇÏ¿© JSON Æ÷¸Ë À¯Áö if Item.DeviceType.Count = 1 then begin // ¹®ÀÚ¿­·Î ÀúÀå: "deviceType": "bluetooth" JHookItem.AddPair('deviceType', Item.DeviceType[0]); end else begin // ¹è¿­·Î ÀúÀå: "deviceType": ["mtp", "cdrom"] JArrDeviceType := TJSONArray.Create; for var S in Item.DeviceType do begin JArrDeviceType.Add(S); end; JHookItem.AddPair('deviceType', JArrDeviceType); end; JHookItem.AddPair('mode', TJSONNumber.Create(Item.Mode)); JHookItem.AddPair('exceptionPath', StringsToJsonArray(Item.ExceptionPath)); JHookItem.AddPair('extension', StringsToJsonArray(Item.Extension)); JHookItem.AddPair('exceptionExtenstion', StringsToJsonArray(Item.ExceptionExt)); JHookProc.AddPair(Item.ProcessName, JHookItem); end; JRule.AddPair('hookProcess', JHookProc); // ÆÄÀÏ ÀúÀå TFile.WriteAllText(FPolicyFilePath, JRoot.ToString); finally JRoot.Free; end; finally FLock.Leave; end; end; procedure TBs1Policy.SaveDeviceControlExceptProcessConfig(ExceptionPath: TStrings); var JsonText: string; JRoot, JDataFlow, JConfigObj, JHookItem: TJSONObject; begin FLock.Enter; try if FileExists(FPolicyFilePath) then begin JsonText := TFile.ReadAllText(FPolicyFilePath); JRoot := TJSONObject.ParseJSONValue(JsonText) as TJSONObject; end else JRoot := TJSONObject.Create; if JRoot = nil then JRoot := TJSONObject.Create; try if JRoot.GetValue('deviceControlConfig') <> nil then begin JRoot.RemovePair('deviceControlConfig').Free; end; JConfigObj := TJSONObject.Create; JConfigObj.AddPair('exceptionPath', StringsToJsonArray(ExceptionPath)); JRoot.AddPair('deviceControlConfig', JConfigObj); TFile.WriteAllText(FPolicyFilePath, JRoot.ToString); finally JRoot.Free; end; finally FLock.Leave; end; end; procedure TBs1Policy.LoadDeviceControlExceptProcessConfig(ExceptionPath: TStrings); var JsonText: string; JRootVal: TJSONValue; JRootObj, JConfigObj: TJSONObject; JArrExceptions: TJSONArray; begin // 1. ÆÄÀÏ Á¸Àç È®ÀÎ if not FileExists(FPolicyFilePath) then Exit; FLock.Enter; try ExceptionPath.Clear; // ±âÁ¸ µ¥ÀÌÅÍ ÃʱâÈ­ // 2. ÆÄÀÏ ÀÐ±â ¹× ÆÄ½Ì JsonText := TFile.ReadAllText(FPolicyFilePath); JRootVal := TJSONObject.ParseJSONValue(JsonText); try // ·çÆ®°¡ JSON °´Ã¼ÀÎÁö È®ÀÎ if (JRootVal <> nil) and (JRootVal is TJSONObject) then begin JRootObj := JRootVal as TJSONObject; // 3. 'deviceControlConfig' °´Ã¼ ã±â if JRootObj.TryGetValue('deviceControlConfig', JConfigObj) then begin // 4. ±× ¾È¿¡¼­ 'exceptionPath' ¹è¿­ ã±â if JConfigObj.TryGetValue('exceptionPath', JArrExceptions) then begin // 5. ¹è¿­ ³»¿ëÀ» TStrings(ExceptionPath)¿¡ Ãß°¡ for var I := 0 to JArrExceptions.Count - 1 do begin ExceptionPath.Add(JArrExceptions.Items[I].Value); end; end; end; end; finally JRootVal.Free; // ÆÄ½ÌµÈ JSON °´Ã¼ ÇØÁ¦ end; finally FLock.Leave; end; end; end.