mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-06 18:24:26 +08:00
531 lines
12 KiB
ObjectPascal
531 lines
12 KiB
ObjectPascal
unit userprivileges;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.Classes, System.Generics.Collections, System.Generics.Defaults,
|
|
Vcl.Graphics, types_helpers;
|
|
|
|
type
|
|
TPrivilegeColumnComparer = class(TComparer<TPrivilege>)
|
|
function Compare(const Left, Right: TPrivilege): Integer; override;
|
|
end;
|
|
|
|
TPrivilegesTreeColumns = class(TList<TPrivilege>)
|
|
private
|
|
FComparer: TPrivilegeColumnComparer;
|
|
public
|
|
constructor Create(const ANetTypeGroup: TNetTypeGroup; const AServerVersion: Integer); virtual;
|
|
destructor Destroy; override;
|
|
|
|
procedure Sort;
|
|
end;
|
|
|
|
|
|
type
|
|
PObjectData = ^TObjectData;
|
|
TObjectData = class(TObject)
|
|
Kind: TNodeObjectKind;
|
|
Caption: string;
|
|
Privileges: TPrivileges;
|
|
Inherites: Boolean;
|
|
InternalSchema: Boolean;
|
|
Changed: Boolean;
|
|
|
|
function Granted(APrivilege: TPrivilege): Boolean; virtual;
|
|
function GroupNode: Boolean; virtual;
|
|
function ToggleInherites: Boolean; virtual;
|
|
function TogglePrivilege(APrivilege: TPrivilege): Boolean; virtual;
|
|
|
|
procedure SaveToDB(const ASchemeName, AGranteeName: string;
|
|
const ANetTypeGroup: TNetTypeGroup;
|
|
const AServerVersion: Integer); virtual;
|
|
end;
|
|
|
|
TObjectDataList = TObjectList<TObjectData>;
|
|
|
|
PUserData = ^TUserData;
|
|
TUserDataList = TList<PUserData>;
|
|
TUserData = class
|
|
Kind: TUserKind;
|
|
Caption: string;
|
|
Changed: Boolean;
|
|
ChangedParts: TUserChangedParts;
|
|
InternalName: string;
|
|
New: Boolean;
|
|
ParentData: PUserData;
|
|
ChildData: TUserDataList;
|
|
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
function AddChild(AChild: PUserData): Integer;
|
|
procedure SetCaption(const ACaption: string; const ASetChanged: Boolean = TRUE);
|
|
procedure SetChanged(const APart: TUserChangedPart);
|
|
end;
|
|
|
|
TUser = class(TObject)
|
|
Username: string;
|
|
Host: string;
|
|
Password: string;
|
|
Cipher: string;
|
|
Issuer: string;
|
|
Subject: String;
|
|
MaxQueries: Integer;
|
|
MaxUpdates: Integer;
|
|
MaxConnections: Integer;
|
|
MaxUserConnections: Integer;
|
|
SSL: Integer;
|
|
Problem: TUserProblem;
|
|
function HostRequiresNameResolve: Boolean;
|
|
end;
|
|
PUser = ^TUser;
|
|
|
|
TUsersList = class(TObjectList<TUser>)
|
|
private
|
|
FUserNames: TStringList;
|
|
FHostNames: TStringList;
|
|
protected
|
|
function GetHostNames(const AUserName: string): TStringList; virtual;
|
|
function GetUserNames: TStringList; virtual;
|
|
public
|
|
constructor Create(AOwnsObjects: Boolean = True); overload;
|
|
destructor Destroy; override;
|
|
|
|
function Add(const Value: TUser): Integer; virtual;
|
|
procedure Clear; virtual;
|
|
|
|
property HostNames[const UserName: string]: TStringList read GetHostNames;
|
|
property UserNames: TStringList read GetUserNames;
|
|
end;
|
|
|
|
TObjectPrivilegeDataList = class;
|
|
|
|
TObjectPrivilegeData = class(TObject)
|
|
private
|
|
FParent: TObjectPrivilegeDataList;
|
|
public
|
|
Kind: TNodeObjectKind;
|
|
Grantee: string;
|
|
Privilege: TPrivilege;
|
|
SchemaName: string;
|
|
ObjectName: string;
|
|
ColumnName: string;
|
|
Index: Integer;
|
|
|
|
constructor Create(AParent: TObjectPrivilegeDataList); virtual;
|
|
end;
|
|
|
|
TObjectPrivilegeDataList = class(TObjectList<TObjectPrivilegeData>)
|
|
private
|
|
FFilterable: Boolean;
|
|
FFilteredList: TObjectPrivilegeDataList;
|
|
public
|
|
constructor Create(AOwnsObjects: Boolean = TRUE;
|
|
AFilterable: Boolean = TRUE); overload;
|
|
destructor Destroy; override;
|
|
|
|
function Append: TObjectPrivilegeData;
|
|
function Filter(const AGrantee: string;
|
|
const AKind: TNodeObjectKind;
|
|
const ASchemaName: string = '';
|
|
const AObjectName: string = '';
|
|
const AColumnName: string = ''): TObjectPrivilegeDataList;
|
|
|
|
function FilteredPrivileges: TPrivileges;
|
|
function Privileges: TPrivileges;
|
|
|
|
property FilteredList: TObjectPrivilegeDataList read FFilteredList;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
SynRegExpr, System.SysUtils, VirtualTrees, dbconnection;
|
|
|
|
{ TObjectData }
|
|
|
|
function TObjectData.Granted(APrivilege: TPrivilege): Boolean;
|
|
begin
|
|
Result:= APrivilege in Self.Privileges;
|
|
end;
|
|
|
|
function TObjectData.GroupNode: Boolean;
|
|
begin
|
|
Result := (Self.Kind = okGroupTables) or
|
|
(Self.Kind = okGroupViews) or
|
|
(Self.Kind = okGroupProcedures) or
|
|
(Self.Kind = okGroupFunctions) or
|
|
(Self.Kind = okGroupTriggers) or
|
|
(Self.Kind = okGroupEvents);
|
|
end;
|
|
|
|
procedure TObjectData.SaveToDB(const ASchemeName, AGranteeName: string;
|
|
const ANetTypeGroup: TNetTypeGroup;
|
|
const AServerVersion: Integer);
|
|
begin
|
|
case ANetTypeGroup of
|
|
ngMySQL:
|
|
begin
|
|
|
|
end;
|
|
|
|
ngMariaDB:
|
|
begin
|
|
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TObjectData.ToggleInherites: Boolean;
|
|
begin
|
|
Self.Inherites:= not Self.Inherites;
|
|
Self.Changed:= TRUE;
|
|
Result:= Self.Inherites;
|
|
end;
|
|
|
|
function TObjectData.TogglePrivilege(APrivilege: TPrivilege): Boolean;
|
|
begin
|
|
if not Self.Inherites then begin
|
|
Changed:= TRUE;
|
|
end;
|
|
if Self.Granted(APrivilege) then begin
|
|
Self.Privileges:= Self.Privileges - [APrivilege];
|
|
Result:= FALSE;
|
|
end else begin
|
|
Self.Privileges:= Self.Privileges + [APrivilege];
|
|
Result:= TRUE;
|
|
end;
|
|
end;
|
|
|
|
|
|
{ TPrivilegesInfo }
|
|
|
|
constructor TPrivilegesTreeColumns.Create(const ANetTypeGroup: TNetTypeGroup;
|
|
const AServerVersion: Integer);
|
|
var
|
|
P: TPrivilege;
|
|
begin
|
|
FComparer:= TPrivilegeColumnComparer.Create;
|
|
inherited Create;
|
|
for P:= Low(TPrivilege) to High(TPrivilege) do begin
|
|
if P.AvailableForServer(ANetTypeGroup, AServerVersion) then begin
|
|
Self.Add(P);
|
|
end;
|
|
end;
|
|
Sort;
|
|
end;
|
|
|
|
destructor TPrivilegesTreeColumns.Destroy;
|
|
begin
|
|
FreeAndNil(FComparer);
|
|
inherited;
|
|
end;
|
|
|
|
|
|
procedure TPrivilegesTreeColumns.Sort;
|
|
begin
|
|
inherited Sort(FComparer);
|
|
end;
|
|
|
|
{ TPrivilegeInfoComparer }
|
|
|
|
function TPrivilegeColumnComparer.Compare(const Left,
|
|
Right: TPrivilege): Integer;
|
|
begin
|
|
if Left.ColorFg = Right.ColorFg then begin
|
|
Result:= CompareStr(Left.ToString, Right.ToString);
|
|
end else begin
|
|
if (Left.ColorFg = TPrivilege.CL_GREEN_FG) and (Right.ColorFg <> TPrivilege.CL_GREEN_FG) then begin
|
|
Result:= -1;
|
|
end else begin
|
|
if (Left.ColorFg = TPrivilege.CL_RED_FG) and (Right.ColorFg = TPrivilege.CL_BLUE_FG) then begin
|
|
Result:= -1;
|
|
end else begin
|
|
Result:= 1;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TUserData }
|
|
|
|
constructor TUserData.Create;
|
|
begin
|
|
ChildData:= TUserDataList.Create;
|
|
end;
|
|
|
|
destructor TUserData.Destroy;
|
|
begin
|
|
FreeAndNil(ChildData);
|
|
inherited;
|
|
end;
|
|
|
|
function TUserData.AddChild(AChild: PUserData): Integer;
|
|
begin
|
|
Result:= -1;
|
|
if not ChildData.Contains(AChild) then begin
|
|
Result:= ChildData.Add(AChild);
|
|
end;
|
|
end;
|
|
|
|
procedure TUserData.SetCaption(const ACaption: string;
|
|
const ASetChanged: Boolean = TRUE);
|
|
var
|
|
D, PD: PUserData;
|
|
begin
|
|
if Caption <> ACaption then begin
|
|
Caption:= ACaption;
|
|
if ASetChanged then begin
|
|
SetChanged(ucpCaption);
|
|
end;
|
|
case Kind of
|
|
ukUser:
|
|
begin
|
|
InternalName:= ACaption;
|
|
for D in ChildData do begin
|
|
D^.InternalName:= '''' + ACaption + '''@''' + D^.Caption + '''';
|
|
if ASetChanged then begin
|
|
D^.SetChanged(ucpCaption);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
ukHost:
|
|
begin
|
|
PD:= ParentData;
|
|
if PD <> NIL then begin
|
|
InternalName:= '''' + PD^.Caption + '''@''' + ACaption + '''';
|
|
end;
|
|
end
|
|
|
|
else begin
|
|
InternalName:= ACaption;
|
|
end;
|
|
|
|
if ASetChanged then begin
|
|
SetChanged(ucpCaption);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TUserData.SetChanged(const APart: TUserChangedPart);
|
|
begin
|
|
if not (APart in Self.ChangedParts) then begin
|
|
Self.Changed:= TRUE;
|
|
Self.ChangedParts:= Self.ChangedParts + [APart];
|
|
case Self.Kind of
|
|
ukGroupUsers: ;
|
|
ukGroupRoles: ;
|
|
ukUser:
|
|
begin
|
|
// N:= tvUsers
|
|
end;
|
|
ukRole: ;
|
|
ukHost: ;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
{ TUser }
|
|
|
|
function TUser.HostRequiresNameResolve: Boolean;
|
|
var
|
|
rx: TRegExpr;
|
|
begin
|
|
rx := TRegExpr.Create;
|
|
rx.Expression := '^(localhost|[\d\.\/\:]+|.*%.*|[\w\d]{4}\:.*)$';
|
|
Result := not rx.Exec(Host);
|
|
rx.Free;
|
|
end;
|
|
|
|
{ TUsersList }
|
|
|
|
constructor TUsersList.Create(AOwnsObjects: Boolean);
|
|
begin
|
|
inherited Create(AOwnsObjects);
|
|
FHostNames:= TStringList.Create;
|
|
FUserNames:= TStringList.Create;
|
|
end;
|
|
|
|
destructor TUsersList.Destroy;
|
|
begin
|
|
FreeAndNil(FHostNames);
|
|
FreeAndNil(FUserNames);
|
|
inherited;
|
|
end;
|
|
|
|
function TUsersList.GetHostNames(const AUserName: string): TStringList;
|
|
var
|
|
User: TUser;
|
|
begin
|
|
if not Assigned(FHostNames) then
|
|
FHostNames:= TStringList.Create
|
|
else
|
|
FHostNames.Clear;
|
|
for User in Self do begin
|
|
if CompareText(User.Username, AUserName) = 0 then begin
|
|
FHostNames.Add(User.Host);
|
|
end;
|
|
end;
|
|
Result:= FHostNames;
|
|
end;
|
|
|
|
function TUsersList.GetUserNames: TStringList;
|
|
begin
|
|
if Assigned(FUserNames) then
|
|
Result:= FUserNames
|
|
else begin
|
|
FUserNames:= TStringList.Create;
|
|
Result:= FUserNames;
|
|
end;
|
|
end;
|
|
|
|
function TUsersList.Add(const Value: TUser): Integer;
|
|
begin
|
|
Result:= inherited Add(Value);
|
|
if FUserNames.IndexOf(Value.Username) = -1 then begin
|
|
FUserNames.Add(Value.UserName);
|
|
end;
|
|
end;
|
|
|
|
procedure TUsersList.Clear;
|
|
begin
|
|
inherited Clear;
|
|
FHostNames.Clear;
|
|
FUserNames.Clear;
|
|
end;
|
|
|
|
{ TObjectPrivilegeData }
|
|
|
|
constructor TObjectPrivilegeData.Create(AParent: TObjectPrivilegeDataList);
|
|
begin
|
|
inherited Create;
|
|
FParent:= AParent;
|
|
end;
|
|
|
|
{ TObjectPrivilegeDataList }
|
|
|
|
constructor TObjectPrivilegeDataList.Create(AOwnsObjects: Boolean = TRUE;
|
|
AFilterable: Boolean = TRUE);
|
|
begin
|
|
inherited Create(AOwnsObjects);
|
|
FFilterable:= AFilterable;
|
|
if FFilterable then begin
|
|
FFilteredList:= TObjectPrivilegeDataList.Create(FALSE, FALSE);
|
|
end else begin
|
|
FFilteredList:= NIL;
|
|
end;
|
|
end;
|
|
|
|
destructor TObjectPrivilegeDataList.Destroy;
|
|
begin
|
|
FreeAndNil(FFilteredList);
|
|
inherited;
|
|
end;
|
|
|
|
function TObjectPrivilegeDataList.Append: TObjectPrivilegeData;
|
|
var
|
|
OPD: TObjectPrivilegeData;
|
|
I: Integer;
|
|
begin
|
|
OPD:= TObjectPrivilegeData.Create(Self);
|
|
I:= Add(OPD);
|
|
OPD.Index:= I;
|
|
Result:= OPD;
|
|
end;
|
|
|
|
|
|
function TObjectPrivilegeDataList.Filter(const AGrantee: string;
|
|
const AKind: TNodeObjectKind; const ASchemaName, AObjectName,
|
|
AColumnName: string): TObjectPrivilegeDataList;
|
|
var
|
|
OPD: TObjectPrivilegeData;
|
|
begin
|
|
Result:= NIL;
|
|
if not FFilterable then begin
|
|
Exit;
|
|
end;
|
|
try
|
|
FFilteredList.Clear;
|
|
case AKind of
|
|
okGlobal:
|
|
begin
|
|
for OPD in Self do begin
|
|
if (OPD.Kind = AKind) and
|
|
(CompareText(OPD.Grantee, AGrantee) = 0) then
|
|
begin
|
|
FFilteredList.Add(OPD);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
okSchema:
|
|
begin
|
|
for OPD in Self do begin
|
|
if (OPD.Kind = AKind) and
|
|
(CompareText(OPD.Grantee, AGrantee) = 0) and
|
|
(CompareText(OPD.SchemaName, ASchemaName) = 0) then
|
|
begin
|
|
FFilteredList.Add(OPD);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
okTable, okView, okProcedure, okFunction:
|
|
begin
|
|
for OPD in Self do begin
|
|
if (OPD.Kind = AKind) and
|
|
(CompareText(OPD.Grantee, AGrantee) = 0) and
|
|
(CompareText(OPD.SchemaName, ASchemaName) = 0) and
|
|
(CompareText(OPD.ObjectName, AObjectName) = 0) then
|
|
begin
|
|
FFilteredList.Add(OPD);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
okColumn:
|
|
begin
|
|
for OPD in Self do begin
|
|
if (OPD.Kind = AKind) and
|
|
(CompareText(OPD.Grantee, AGrantee) = 0) and
|
|
(CompareText(OPD.SchemaName, ASchemaName) = 0) and
|
|
(CompareText(OPD.ObjectName, AObjectName) = 0) and
|
|
(CompareText(OPD.ColumnName, AColumnName) = 0) then
|
|
begin
|
|
FFilteredList.Add(OPD);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
Result:= FFilteredList;
|
|
end;
|
|
end;
|
|
|
|
function TObjectPrivilegeDataList.FilteredPrivileges: TPrivileges;
|
|
var
|
|
OPD: TObjectPrivilegeData;
|
|
begin
|
|
Result:= [];
|
|
for OPD in FFilteredList do begin
|
|
Result:= Result + [OPD.Privilege];
|
|
end;
|
|
end;
|
|
|
|
function TObjectPrivilegeDataList.Privileges: TPrivileges;
|
|
var
|
|
OPD: TObjectPrivilegeData;
|
|
begin
|
|
Result:= [];
|
|
for OPD in Self do begin
|
|
Result:= Result + [OPD.Privilege];
|
|
end;
|
|
end;
|
|
|
|
end.
|