242 lines
7.6 KiB
Plaintext
242 lines
7.6 KiB
Plaintext
#ifndef AppVersion
|
|
#define AppVersion "0.2.8"
|
|
#endif
|
|
#ifndef SourceRoot
|
|
#error SourceRoot must point at the self-contained Companion publish directory.
|
|
#endif
|
|
#ifndef OutputRoot
|
|
#error OutputRoot must point at the installer output directory.
|
|
#endif
|
|
|
|
[Setup]
|
|
AppId={{EDEB45E4-41CB-4D7A-A479-4073A1A08B93}
|
|
AppName=Lumi Companion
|
|
AppVersion={#AppVersion}
|
|
AppVerName=Lumi Companion {#AppVersion}
|
|
AppPublisher=OokamiKunTV
|
|
AppCopyright=Copyright (c) 2026 OokamiKunTV
|
|
DefaultDirName={localappdata}\Programs\Lumi Companion
|
|
DefaultGroupName=Lumi Companion
|
|
DisableProgramGroupPage=yes
|
|
PrivilegesRequired=lowest
|
|
ArchitecturesAllowed=x64compatible
|
|
ArchitecturesInstallIn64BitMode=x64compatible
|
|
OutputDir={#OutputRoot}
|
|
OutputBaseFilename=Lumi.Companion-Setup
|
|
Compression=lzma2/ultra64
|
|
SolidCompression=yes
|
|
WizardStyle=modern
|
|
SetupLogging=yes
|
|
CloseApplications=yes
|
|
CloseApplicationsFilter=Lumi.Companion.App.exe
|
|
RestartApplications=no
|
|
UninstallDisplayName=Lumi Companion
|
|
UninstallDisplayIcon={app}\Lumi.Companion.App.exe
|
|
VersionInfoCompany=OokamiKunTV
|
|
VersionInfoCopyright=Copyright (c) 2026 OokamiKunTV
|
|
VersionInfoDescription=Lumi Companion installer
|
|
VersionInfoProductName=Lumi Companion
|
|
VersionInfoProductTextVersion={#AppVersion}
|
|
LicenseFile={#SourceRoot}\legal\LUMI-COMPANION-LICENCE.txt
|
|
InfoBeforeFile={#SourceRoot}\legal\PRIVACY-NOTICE.txt
|
|
InfoAfterFile={#SourceRoot}\legal\THIRD-PARTY-NOTICES.txt
|
|
|
|
[Files]
|
|
Source: "{#SourceRoot}\Lumi.Companion.App.exe"; DestDir: "{app}"; Flags: ignoreversion
|
|
Source: "{#SourceRoot}\components\*"; DestDir: "{app}\components"; Flags: ignoreversion recursesubdirs createallsubdirs
|
|
Source: "{#SourceRoot}\legal\*"; DestDir: "{app}\legal"; Flags: ignoreversion recursesubdirs createallsubdirs
|
|
|
|
[Icons]
|
|
Name: "{autoprograms}\Lumi Companion"; Filename: "{app}\Lumi.Companion.App.exe"
|
|
Name: "{autoprograms}\Lumi Companion - Legal and Privacy"; Filename: "{app}\legal\LEGAL-README.txt"
|
|
|
|
[Run]
|
|
Filename: "{app}\Lumi.Companion.App.exe"; Description: "Open Lumi Companion"; Flags: nowait postinstall skipifsilent
|
|
|
|
[Code]
|
|
var
|
|
PairingPackagePath: String;
|
|
PairingHost: String;
|
|
PairingOperatorName: String;
|
|
PairingOperatorContact: String;
|
|
PairingPrivacyUrl: String;
|
|
HostAcknowledgementPage: TInputOptionWizardPage;
|
|
|
|
function LocatePairingPackage: String;
|
|
var
|
|
FindRec: TFindRec;
|
|
begin
|
|
Result := '';
|
|
if FindFirst(ExpandConstant('{src}\*.lumi-pairing.json'), FindRec) then
|
|
begin
|
|
try
|
|
Result := AddBackslash(ExpandConstant('{src}')) + FindRec.Name;
|
|
finally
|
|
FindClose(FindRec);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function JsonStringValue(const Json: String; const Key: String): String;
|
|
var
|
|
Marker: String;
|
|
Tail: String;
|
|
MarkerPos: Integer;
|
|
ColonPos: Integer;
|
|
EndQuotePos: Integer;
|
|
begin
|
|
Result := '';
|
|
Marker := '"' + Key + '"';
|
|
MarkerPos := Pos(Marker, Json);
|
|
if MarkerPos = 0 then
|
|
Exit;
|
|
|
|
Tail := Copy(Json, MarkerPos + Length(Marker), Length(Json));
|
|
ColonPos := Pos(':', Tail);
|
|
if ColonPos = 0 then
|
|
Exit;
|
|
|
|
Tail := Trim(Copy(Tail, ColonPos + 1, Length(Tail)));
|
|
if (Length(Tail) < 2) or (Tail[1] <> '"') then
|
|
Exit;
|
|
|
|
Tail := Copy(Tail, 2, Length(Tail));
|
|
EndQuotePos := Pos('"', Tail);
|
|
if EndQuotePos = 0 then
|
|
Exit;
|
|
|
|
Result := Copy(Tail, 1, EndQuotePos - 1);
|
|
end;
|
|
|
|
function LoadPairingJson(const PackagePath: String; var Json: String): Boolean;
|
|
var
|
|
Lines: TArrayOfString;
|
|
Index: Integer;
|
|
begin
|
|
Result := False;
|
|
Json := '';
|
|
if (PackagePath = '') or not LoadStringsFromFile(PackagePath, Lines) then
|
|
Exit;
|
|
|
|
for Index := 0 to GetArrayLength(Lines) - 1 do
|
|
begin
|
|
if Index > 0 then
|
|
Json := Json + #10;
|
|
Json := Json + Lines[Index];
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function ReadPairingHost(const Json: String): String;
|
|
var
|
|
Candidate: String;
|
|
LowerCandidate: String;
|
|
begin
|
|
Result := '';
|
|
Candidate := JsonStringValue(Json, 'host');
|
|
LowerCandidate := Lowercase(Candidate);
|
|
if ((Pos('https://', LowerCandidate) = 1) or (Pos('http://', LowerCandidate) = 1)) and
|
|
(Length(Candidate) <= 500) then
|
|
Result := Candidate;
|
|
end;
|
|
|
|
procedure InitializeWizard;
|
|
var
|
|
HostDisplay: String;
|
|
Explanation: String;
|
|
OperatorDetails: String;
|
|
Json: String;
|
|
begin
|
|
PairingPackagePath := LocatePairingPackage;
|
|
if LoadPairingJson(PairingPackagePath, Json) then
|
|
begin
|
|
PairingHost := ReadPairingHost(Json);
|
|
PairingOperatorName := Copy(JsonStringValue(Json, 'operator_name'), 1, 200);
|
|
PairingOperatorContact := Copy(JsonStringValue(Json, 'operator_contact'), 1, 300);
|
|
PairingPrivacyUrl := Copy(JsonStringValue(Json, 'privacy_url'), 1, 500);
|
|
end;
|
|
|
|
if PairingHost <> '' then
|
|
HostDisplay := PairingHost
|
|
else
|
|
HostDisplay := 'No paired Lumi host was identified beside this installer.';
|
|
|
|
OperatorDetails := '';
|
|
if PairingOperatorName <> '' then
|
|
OperatorDetails := OperatorDetails + #13#10 + 'Operator name: ' + PairingOperatorName;
|
|
if PairingOperatorContact <> '' then
|
|
OperatorDetails := OperatorDetails + #13#10 + 'Operator contact: ' + PairingOperatorContact;
|
|
if PairingPrivacyUrl <> '' then
|
|
OperatorDetails := OperatorDetails + #13#10 + 'Privacy information: ' + PairingPrivacyUrl;
|
|
|
|
Explanation :=
|
|
'This copy of Lumi Companion is intended to connect to:' + #13#10#13#10 +
|
|
HostDisplay + OperatorDetails + #13#10#13#10 +
|
|
'The person or organisation controlling that Lumi installation is the Host Operator. ' +
|
|
'The Host Operator is responsible for the Hosted Service it controls, including server configuration, ' +
|
|
'access, server-side data processing, retention, integrations, and required user notices. ' +
|
|
'OokamiKunTV is the software developer and is not automatically the operator of an independently hosted Lumi installation. ' +
|
|
'Responsibility always follows the actual facts and applicable law.';
|
|
|
|
HostAcknowledgementPage := CreateInputOptionPage(
|
|
wpInfoBefore,
|
|
'Lumi host and data responsibility',
|
|
'Review the host that will receive Companion data.',
|
|
Explanation,
|
|
False,
|
|
False);
|
|
HostAcknowledgementPage.Add(
|
|
'I understand which Lumi host this Companion will use and that the Host Operator controls its server-side service and processing.');
|
|
end;
|
|
|
|
function NextButtonClick(CurPageID: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
{ A silent deployment is an administrator/operator action and has no wizard
|
|
UI in which an interactive acknowledgement can be collected. }
|
|
if WizardSilent then
|
|
Exit;
|
|
|
|
if (HostAcknowledgementPage <> nil) and (CurPageID = HostAcknowledgementPage.ID) and
|
|
not HostAcknowledgementPage.Values[0] then
|
|
begin
|
|
MsgBox(
|
|
'Confirm that you understand the host and operator responsibility before continuing.',
|
|
mbInformation,
|
|
MB_OK);
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
procedure ImportPairingPackage;
|
|
var
|
|
SourcePath: String;
|
|
TargetPath: String;
|
|
begin
|
|
{ Portable and installed builds share the same DPAPI credential directory. Do
|
|
not create another authorized device merely because an existing user moves
|
|
the executable into its durable installed location. }
|
|
if FileExists(ExpandConstant('{localappdata}\Lumi\Companion\device.credential')) then
|
|
Exit;
|
|
|
|
SourcePath := PairingPackagePath;
|
|
if SourcePath = '' then
|
|
SourcePath := LocatePairingPackage;
|
|
if SourcePath = '' then
|
|
Exit;
|
|
|
|
TargetPath := AddBackslash(ExpandConstant('{app}')) + ExtractFileName(SourcePath);
|
|
if not CopyFile(SourcePath, TargetPath, False) then
|
|
MsgBox(
|
|
'Lumi Companion was installed, but its one-time pairing package could not be imported. ' +
|
|
'Open Companion and choose the pairing file manually.',
|
|
mbError,
|
|
MB_OK);
|
|
end;
|
|
|
|
procedure CurStepChanged(CurStep: TSetupStep);
|
|
begin
|
|
if CurStep = ssPostInstall then
|
|
ImportPairingPackage;
|
|
end;
|