Variable dauerhaft in App speichern?

Hallo zusammen, ich habe mein erstes Desktop Programm am Mac mit Xojo geschrieben und suche eine Möglichkeit die Seriennummer des Rechners dauerhaft in dem Programm zu speichern. Hab bis jetzt nur mit Applescript gearbeitet und dort haben Properties Ihren Wert so lange behalten, bis man das Programm erneut kompiliert hat. Hintergrund ist, dass ich die Weitergabe des Programms auf diesem Weg unterbinden will. Wenn es eine andere Möglichkeit gibt, wäre ich für Tipp offen.

Danke für eure Hilfe!

Das wird immer mal wieder probiert und es gibt immer wieder Flle, wo das nicht funktioniert.

Aber zu Deiner Frage: auf dem Mac wird das mit plist-Dateien gemacht. Es gibt mehrere verfgbare Source-Code-Libraries dafr. Z.B. Macoslib, siehe https://github.com/macoslib/macoslib . Das ist zwar ein recht groer Brocken, aber das Verwenden von TTsPrefs ist ganz einfach.

Hallo Beatrix, vielen Dank für die schnelle Antwort. Ich suchte halt eine Möglichkeit die der Kunden nicht so einfach manipulieren kann wie eine externe Datei. Das TTsPrefs sehe ich mir am Wochenende an.
Bis jetzt speichere ich die Seriennummer beim Kunden in den Defaultwert einer Property, kompiliere dann das Programm und vergleiche beim Start des Programms die aktuell ausgelesene Seriennummer mit dem hinterlegten Property-Wert.
Kann man den vielleicht den Wert einer Property durch eine Routine aktualisieren?

Danke

Dafür sind die Properties da :slight_smile:

Alternativ kann man auch eine verschlüsselte SQLite Datenbank dafür missbrauchen. Das macht es einfach und CrossPlattform kompatibel. :slight_smile:

Vielen Dank für die Hilfe, da werde ich am Wochenende mal in die Examples zu SQLite schauen.

Kleine Starthilfe.

Erstelle ein Modul und füge diesem eine db Property als SQLiteDatabase und eine dbKey Constante als String hinzu. In der Konstanten speicherst Du Deinen Datenbank verschlüsselung Schlüssel.

Dann schreibe in Dein App.Open Event folgenden Code:

[code]db = New SQLiteDatabase

db.databaseFile = SpecialFolder.ApplicationData.Child(App.LongVersion).Child(App.LongVersion + “.sql”)

If db.DatabaseFile <> Nil Then
If db.databaseFile.exists = True then
// Es existiert bereits eine Datenbank, als verbinden wir uns mit selbiger…
DB_ConnectToDatabase
Else
// Es existiert keine Datenbank, also erstellen wir eine…
DB_CreateDatabaseFile
End If
Else
// Etwas grundlegendes beim Dateizugriff ist schief gelaufen…
End if[/code]

Erstelle im o.a. Modul eine DB_ConnectToDatabase Methode. In dieser steht etwas wie:

db.EncryptionKey = dbKey If Not db.Connect Then // Es ist etwas schief gelaufen. Wir kommen nicht an die Datenbank ran... End If

Im oben angegebenen Modul, erstelle eine DB_CreateDatabaseFile Methode. In dieser Methode erstellst Du ein FolderItem (“f” z.B.) und erstellst eine Datenbank.

[code] Dim f as FolderItem
Dim result as Boolean

f=New FolderItem(SpecialFolder.ApplicationData.Child(App.LongVersion))
If f.Exists = False Then
f.CreateAsFolder
If Not f.Exists Then
// Wir konnten den Ordner nicht erstellen. Panik ist angesagt…
End If
End If

f=New FolderItem(SpecialFolder.ApplicationData.Child(App.LongVersion).Child(App.LongVersion + “.sql”))

db=New SQLiteDatabase

db.databaseFile=f
db.EncryptionKey = dbKey
result=db.CreateDatabaseFile

DB_ConnectToDatabase

db.SQLExecute("CREATE TABLE // erstelle hier Deine Tabelle(n)

db.Commit[/code]

Von hier an kannst Du ganz einfach auf Deine Datenbank zugreifen.
Zum Beispiel so:

[code] Dim rs As RecordSet = db.SQLSelect(“SELECT app_id FROM apps ORDER BY name;”)

If rs<>Nil And Not rs.EOF Then
While Not rs.EOF
ListBoxApps.Append rs.IdxField(1)
rs.MoveNext
Wend
End If[/code]

Dieses Beispiel wurde für ein Mac System geschrieben. Du möchtest sicher am FolderItem, also am Speicherort der Datenbank was ändern . Ausserdem ist ein Verschlüsselung Schlüssel als Konstante nicht sehr sicher…
Die Datenbank muss nicht die Dateiendung SQL tragen. Du kannst Sie auch gerne BIN SET oder was auch immer enden lassen. Nimm meine Kommentare im Source nicht ernst, ich habe nur diverse Routinen für das Forum entfernt und statt dessen Quatsch rein geschrieben. :wink:
Der o.a. Code wird nach einem Copy&Paste nicht gleich funktionieren. Du musst diverse Parameter an Deine Bedürfnisse anpassen.

Ich hoffe das erleichtert Dir den Einstieg in die Materie. :slight_smile:

Leute!

Das Einfachste ist, eine eindeutige Kennung des Macs, z.B. dessen MAC-Adresse (dies verwendet auch Apples App Store, um zu prüfen, ob eine App für den Mac schon authorisiert ist) mit der Seriennummer zu verwurtscheln, und das Ergebnis in einer Datei, z.B. den Preferences (über TTsPrefs) zu sichern. Dann beim Start den Wert wieder überprüfen.

So macht das auch der Code in “CertTools” in MacOSLib - den und den Demo-Code, der das testet, wäre ein guter Start (allerdings wird dabei, von Apple, der Prüfcode in der App direkt abgelegt - das darfst du nicht machen, du mußt es stattdessen in einer Datei ablegen, die im Prefs- oder ApplicationSupport-Unterordner liegt. Klar?)

Das ist nicht gut, denn da hast du pro Version deiner App einen neuen Ordner (und es fehlt natürlich der Code, der den Ordner erstmal anlegt). So müßte der User ja bei jedem manuellen Update die Registrierung neu eingeben! Außerdem ist es auch nicht Apples (und auch nicht Microsofts) Wille, mehr als einen Ordner pro App im AppSupport-Ordner zu haben.

Also, richtig wäre es eher so:

const appName = "SuperApp" // Der name deiner App, kann man leider nicht anders abfragen dim appFolder as FolderItem = SpecialFolder.ApplicationData.Child(appName) if not appFolder.Exists then appFolder.CreateAsFolder

Danke @Thomas Tempelmann, aber wozu habe ich dann die o.a. Bemerkungen hinzugefügt? :wink:

Das sollte doch nur eine Starthilfe und keine fertige Lösung werden.

Alles wird gut… :slight_smile:

Sascha, ich habe das korrigiert, weil der Code offenbar von deinem eigenen Programm stammt, d.h. DU SELBST macht das falsch. Stört dich das nicht?

Es sei denn, du trägst in den App-Build-Settings unter “Long Version” nur den Namen ein, ohne Versionsnummer? Dann paßt dein Code, aber das ist ja nicht offensichtlich. Daher meine Warnung, um darauf hinzuweisen.

Ach so. Na dann, vielen Dank für den Hinweis. :slight_smile:

PS: Ja, Du gehst Recht in Deiner Annahme.

Hmm, nun wird mir langsam klar, meine Antwort nicht so ganz zu Normens Anforderung pat:

Mein Vorschlag ist dafr gedacht, da man sicherstellt, da eine App nur auf bestimmten Macs luft. D.h, die App kann auch nicht ohne Erzeugung eines neuen Codes auf einem anderen Mac installiert werden. Das ist es gar nicht, was Normen will, oder?

Normen, lies mal meinen Artikel zum Absichern von Lizenzen, ich hoffe, Englisch ist kein Problem: http://www.tempel.org/UsingAquaticPrime

Noch mehr zu meinem obigen Kommentar:

Das “Verwurscheln” von Ser-Nr mit Mac-Kennung ist natrlich auch eine Kunst. Am Einfachsten macht man das so, vorausgesetzt, beide Werte liegen als Strings vor.

[code]const secretKey = “for” // Eine kurzer String, der nie verndert wird, aber bei jeder App anders sein sollte.

dim regCode as String = … // Hier die Ser-Nr laden, die z.B. (sichtbar) in den Prefs abgelegt ist.
dim hashedCode as String = … // Hier den erzeugten Hash-Code laden, der z.B. (sichtbar) in den Prefs abgelegt ist.

dim macID as MemoryBlock = CertTools.DeviceGUID // may be nil, e.g. on Hackintosh PCs!
dim gewurschtel as MemoryBlock = macID + secretKey + regCode
dim currHash as new MemoryBlock(20) ’ SHA_DIGEST_LENGTH
declare sub SHA1 lib “/usr/lib/libcrypto.dylib” (d as Ptr, n as Int32, md as Ptr)
SHA1 (gewurschtel, gewurschtel.Size, currHash)
if StrComp (currHash, hashedCode, 0) = 0 then
// pat!
else
// ungltig
end if[/code]

Der Code oben ist fr das Prfen, ob die Ser-Nr zu dem Mac passt.
Das “Verwurschteln” passiert durch das Berechnen eines Hash-Codes aus der Ser-Nr und der Mac-Kennung. Der Trick ist, da der User, der (hchstwahrscheinlich) nicht den Code des Programms analysieren kann und somit nicht wei, wie er beim Kopieren des Programms auf einen anderen Mac beide Werte (Ser-Nr und Hash-Code) korrekt setzen muss, damit die Kopie auch luft. D.h, hier wird mit der SHA1-Funktion eine simple Verschlsselung von Daten vorgenommen, und nur du als Programmierer weit, wie die Verschlsselung funktioniert (damit die nicht blind erraten werden kann, fgt man einen secretKey hinzu, wie oben zu sehen).

Wenn man nun dem Kunden die App verkauft, lt man ihn erst ein kl. Programm starten, das die Mac-ID ausliest. Die wird dann an den Hersteller (hier: Normen) bermittelt und der erzeugt dann den Hash-Code aus der Ser-Nr, dem secretKey und der macID, und teilt den Hash-Code dem User mit. Den mu das Programm dann speichern, zusammen mit der Ser-Nr, so da beim Start der App beide wieder gelesen und mit obigem code berprft werden knnen.

Ist das Verstndlich, Normen?

Allerdings willst du es evtl. gar nicht so aufwndig machen. Kommt auf den Preis der App an - wenn sie 1000ekostet und du nur ein paar Kunden hast, dann kannst du das so machen, weil du die Kunden dann auch direkt betreuen kannst. Bei einer billigen App, die 1000fach verkauft wird, mut du das automatisieren, mit einem Server. Das wird aufwndig. Bedenke auch, da Kunden oft genug auf einen neuen Mac wechseln wollen. Wenn dann deine Hashcode-Generierung nicht mehr zur Verfgung steht, sind die Kunden sauer (aber dann bist du eh aus dem Geschft raus, vermutlich).

Sorry Leute, dass ich mich erst jetzt wieder melde.
Vielen Dank für die angeregte Diskussion, ich werde wohl die nächsten Wochenenden damit verbringen die einzelnen Möglichkeiten auszuprobieren. Programmieren ist nicht mein Haupterwerb und ich muss noch so viel lernen.
Es war wirklich hauptsächlich das Ziel, dass kein erfahrener EDV-Betreuer die installierte Software auf einen anderen Rechner oder bei einem anderen Kunden installiert.
Für das erste Projekt war mir ein eigener Authentifizierungsserver im Internet einfach zu schwierig.