Sauvegarde
Jijo
Membre
J'ai essayé plusieurs tutoriels et je n'arrive toujours pas a sauvegarder mot de passe et login dans un plist à la fermeture de mon appli et à charger la plist au lancement.
Je ne sais pas non plus s'il faut passer par User Defaults Controller dans Interace Builder.
Merci
Je ne sais pas non plus s'il faut passer par User Defaults Controller dans Interace Builder.
Merci
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Surtout quand dans OSX, il y a le KeyChain qui permet de stocker des infos sous forme protégée.
Dans ce post il y a des pistes pour savoir utiliser le KeyChain (donc comment écrire puis lire un mot de passe) depuis une appli cocoa.
Sinon j'ai trouvé ceci:
http://developer.apple.com/documentation/Security/Conceptual/keychainServConcepts/02concepts/chapter_2_section_4.html
La section AddingSimpleKeychainServicestoYourApplication du pdf est ce que je veux faire.
Par contre je n'arrive pas a implémenter une classe pour les methodes utiliser car je voudrais executer l'ajout SecKeychainAddGenericPassword dans la methode action si la connexion est établie.
J'ai vu que le plugin Smugmug d'iPhoto enregistrait dans le trousseau de clef dans utilitaire donc cela est faisable.
Bizarre car chez moi ça compile bien.
Y'a des warnings dus à l'utilisation des méthodes depercated (surtout lié aux méthodes cstring de NSStrings), mais cela n'empêche pas la compil et reste fonctionnel.
Par contre j'ose imaginer que t'as oublié d'importer le framework Security à ton projet.
Donc le linkage lui plante.
Ajoute ce framework (clic-droit sur "Frameworks" dans "groups & files" > Add... > Existing Frameworks > navigation jusqu'à /System/libray/Frameworks puis sélection du Security.framework), puis recompile.
De toute façon, les 2 fichiers .h et .m ne sont là qu'à titre d'exemple.
A toi de picorer ce qui te sera utile dedans (et donc de modifier les méthodes deprecated par les nouvelles méthodes à utiliser).
:)beta:
Du coup j'ai pu réaliser la 1ère partie c'est a dire intégrer mon login et mot de passe dans le trousseau de cléf session principale sans créer un fichier keychain.
SecKeychainAddGenericPassword (
NULL, // default keychain
6, // length of service name
"plugin", // service name
[[login stringValue] length], // length of account name
[[login stringValue] cString], // account name
[[password stringValue] length], // length of password
[[password stringValue] cString], // pointer to password data
NULL // the item reference
);
Cependant je ne sais pas comment charger le mot de passe et le login.
- (NSString *)passwordForServiceName:(NSString *)servicename account:(NSString *)account
{
OSStatus err;
UInt32 passl;
void *pass;
err=SecKeychainFindGenericPassword(_kcref, [servicename length], [servicename cString],
[account length], [account cString],
&passl, &pass, NULL);
return [[[NSString alloc] initWithCString:pass length:passl] autorelease];
}
Cette fonction est celle qui conviendrait pourtant il faut passer en paramètre l'account et comme on le voit sur la photo l'account est mon login.
Comment charger un login et un mot de passe s'il faut connaà®tre le login pour connaà®tre le mot de passe.
Si je place cette fonction dans awakeFromNib je me trouve dans l'incapabilité de connaà®tre le login.
Sinon j'ai essayé avec l'itemRef mais je ne suis pas arrivé a charger.
Une fois récupéré, tu peux alors aller dans le keychain pour accéder au mot de passe.
Si le "account name" n'existe pas (donc première utilisation du plugin), alors tu le demandes à l'utilisateur.
Pour l'instant avec NSUserDefaults* prefs = [NSUserDefaults standardUserDefaults] j'ai pu stocker l'account et charger le mot de passe du trousseau de clef.
Cependant le fichier plist correspondant est com.apple.iPhoto. Du coup je dois créer un fichier plist independant que pour mon plugin.
J'ai trouvé ce-ci
http://www.projectomega.org/contents/fr/php/oreilly/cocoa/MacOSX_Cocoa_11.pdf
NSString *recordsFile;
- (void)awakeFromNib
{
recordsFile = @$(HOME)/Library/Preferences/iPhotoPlugin.plist;
recordsFile = [recordsFile stringByExpandingTildeInPath];
[recordsFile retain];
NSUserDefaults * prefs = [[NSMutableArray alloc] initWithContentsOfFile:recordsFile];
if ( nil == prefs )
{
prefs = [[NSMutableArray alloc] init];
}
else
{
id kc = [[KEYCHAINAccess alloc] init];
// récupération
NSString * account = [prefs stringForKey:@account];
NSString * passe =[kc passwordForServiceName:@iPhotoPlugin account:account];
// ajout du login et mot de passe au charrgement
[o_login setStringValue:account];
[o_password setStringValue:passe];
}
}
J'ai mis NSUserDefaults comme type mais je ne sais pas si cela est correct.
Deplus le fichier plist ne se crée pas.
En gros je veux juste créer un fichier plist qui contient l'account.Il y a peut-être quelque chose de plus simple.
Pour créer un plist dans le dossier preferences, on peut utiliser setPersistentDomain: forName:
et pour le récupérer:
CA c'est utile !
En revanche je trouve ça assez chiant qu'il demande le password à chaque fois (quasiment) qu'on lance son application.
"Machin wants to access the machin.keychain"
{
// création du dictionnaire
NSMutableDictionary * dict=[[NSMutableDictionary alloc] init];
// remplissage de ce dictionnaire
[dict setObject:@MyAccount forKey:@account];
// création du dictionnaire dans le dossier préférence ($(HOME/Library/Preferences/MyPlist.plist")
[[NSUserDefaults standardUserDefaults] setPersistentDomain:dict forName:@MyPlist];
// extraction du dictionnaire ne marche pas
NSDictionary * Extractionplist=NSUserDefaults standardUserDefaults] persitentDomainForName:@"MyPlist"];<br /> NSString * login =[[NSString alloc]initWithString:[Extractionplist objectForKey:@"account";
id kc = [[KEYCHAINAccess alloc] init];
// recherche du mot de passe dans le Keychain suivant le service et le compte de l'utilisateur
NSString * passe =[kc passwordForServiceName:@plugin account:login];
// ajout du login et mot de passe dans les NSTextField au chargement
[login setStringValue: login];
[password setStringValue:passe];
}
Pour te répondre Eaglelouk je stock bien mon login et mon mot de passe dans le keychain, cependant pour utiliser la fonction de recherche du mot de passe passwordForServiceName je dois lui passer en paramètre le login.
Donc je me vois obligé de stocker le login dans une plist qui deplus doit être différente de celle par défaut faite par NSUserDefaults* prefs = [NSUserDefaults standardUserDefaults] car je fais un plugin et cela ne serai pas propre de le stocker dans com.apple.iPhoto.
Ainsi le login est en clair mais le mot de passe est protégé.
La création de la plist MyPlist marche, mais je n'arrive pas encore à extraire ma variable account de celle -ci.
Sinon sans la création du fichier plist que je peux créer et installer avec le package d'installation,je voudrais essayer de charger le NSDictionary de cette plist.
Avec le tuto de project omega que j'ai trouvé ici --> http://www.projectomega.org/contents/fr/php/oreilly/cocoa/MacOSX_Cocoa_11.pdf j'ai essayé de charger les données. Cela s'éxécute mais records est vide après chargement.
NSString * recordsFile;
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// je ne sais pas quoi mettre pour récupérer e non de l'utilisateur
recordsFile = @$(HOME)/Library/Preferences/MyPlist.plist;
recordsFile = [recordsFile stringByExpandingTildeInPath];
[recordsFile retain];
NSMutableArray * records = [[NSMutableArray alloc] initWithContentsOfFile:recordsFile];
[pool release];
Ce que je veux faire est simple, je veux charger les variables d'une plist donnée et pouvoir à la fermeture de l'application modifier oui ou non les variable de la plist.
Merci
Je sais pas si cela est faisable.
Sinon, ce code marche chez moi:
/Users/nomUser/Library/Preferences/MyPlist.plist {
MyPlist = {
account = monLogin;
};
}
J'ai essayé d'extraire la variable account comme j'avais déjà pu le faire auparavant mais cela ne marche pas.
NSLog(@Variable account =%@",[dic objectForKey:@account]);
Console :
Variable account =(null)
Merci
Comment l'enregistres tu ?
Car on dirait un plist au format texte.
Donc tu ne passes par par les user defaults.
Il nous faudrait plus de code pour voir ce qui se passe en amont (notamment comment tu charges le plist dans la dictionnaire dic).
Dans un projet cocoa vierge, dans awakeFromNib, colle ce code:
dans la console tu dois avoir:
En installant mon plugin iPhoto le package installe le plugin ainsi que la plist MyPlist dans le dossier /Users/NomDuCOmpteCOurant/Library/Preferences/MyPlist.plist
J'utilise une plist autre que celle utilisée pour user defaults car sinon je modifierai la plist com.apple.iPhoto ce qui ne serai pas propre à mon goût même si certain plugin le font.
Ensuite au lancement de mon plugin:
Chargement de la plist dans awakeFromNib
- (void)awakeFromNib
{
// chargement du dictionaire contenu dans le fichier MyPlist.plist
NSString *prefPath=[NSString stringWithFormat:@%@/%@/%@",NSHomeDirectory(),@Library/Preferences,@MyPlist.plist];
NSDictionary *dic=[NSDictionary dictionaryWithContentsOfFile:prefPath];
// ce que je voudrais faire
// recupération du login contenu dans dic sous forme NSString
NSString * monLogin = [dic objectForkey:@account];
// recherche du password pour le login chargé et pour le service iPhotoPlugin (nom de mon plugin) dans le fichier du KEYCHAIN (trousseau de clefs)
id kc = [[KEYCHAINAccess alloc] init];
NSString * passe =[kc passwordForServiceName:@iPhotoPlugin account: monLogin];
// ajout du login et mot de passe dans les NSTexfields
[login setStringValue: login];
[password setStringValue:passe];
}
Si la connexion se fait avec un autre compte c'est à dire avec un autre login que celui chargé, aprés connexion on modifie la valeur de account dans MyPlist pour la remplacer par celle du nouveau login pour le sauvegarder.
Il me manque la récupération de la variable account en NSString et la modification de celle-ci pour la sauvegarde.
Voilà
Si ce n'est pas clair dites le moi.
Merci
Photo de la fenêtre chargée au lancement du plugin avec le login et mot de passe.
Donc plus la peine de se prendre le tête sur mon problème.
Merci quand même d'avoir essayé.
On se prend pas la tête.
Mais tu donnes si peu de code que c'est impossible de t'aider.
Je suis sûr que ta ligne qui charge MyPlist dans le dictionnaire dic est pourrie.
Mais c'est tout ce que je peux dire sans autre info.
La console affiche
MyPlist = {
account = monLogin;
};
}
Sauf que je n'arrive pas à extraire la variable account en type NSString.
Peux tu afficher la ligne qui charge le dictionnaire telle qu'elle est dans ton code ?
NSString * prefPath=[NSString stringWithFormat:@%@/%@/%@",NSHomeDirectory(),@Library/Preferences,@MyPlist.plist];
// extraction du dictionnaire
NSDictionary * dic=[NSDictionary dictionaryWithContentsOfFile:prefPath];
Voilà comment je charge mon dictionnaire
Bien.
Je vois un problème potentiel de problème mémoire (perte du dictionnaire dic) à cause de la méthode de classe dictionaryWithContentsOfFile: utilisée sans retain (cette méthode renvoie un NSDictionary en autorelease : il sera donc purger de la mémoire assez vite si tu ne fais rien).
Remplace ta ligne [tt]NSDictionary * dic=[NSDictionary dictionaryWithContentsOfFile:prefPath];[/tt] par :
ou mieux, par :
NSDictionary * dic=[[NSDictionary alloc] initWithContentsOfFile:prefPath];
NSLog(@%@ ",dic);
NSLog(@Variable account =%@",[dic objectForKey:@account]);
Console:
{
MyPlist = {
account = monLogin;
};
}
Variable account =(null)
Dans les 2 cas que tu me proposes [dic objectForKey:@account] apparaà®t comme null.
Ton dico contient un autre dico !!!?
essaye ça pour voir:
Tu peux aussi vérifier la structure de ton plist avec Property List Editor.
Donc son dictionary est bien, d'après le log et vu comment il l'imprime, et ce depuis le début, un dictionnaire contenant une unique clé "MyPlist"... associée... à son dictionary contenant, lui, sa clé "account" !
Et donc il faut bien faire comme tu dis [tt][[dic objectForKey:@MyPlist] objectForKey:@account][/tt] pour le coup.
Reste à comprendre pourquoi son dictionnaire est lui-même encapsulé dans un doctionnaire avec la clé "MyPlist", je pense que c'est dû au fait qu'il le crée avec les userDefaults et enregistre un persistantDomainName.
D'ailleurs ce qui me gène c'est que tu sembles enregistrer tes données avec userDefaults (mais pas le shared, bien celui pour lequel tu as rajouté ton persistant domain)... mais la lecture tu la fais comme une lecture plus bas niveau, en donnant le chemin du fichier plist pour le lire (et sur lequel tu n'es pas sensé te baser car les userDefaults pourraient être stockés à un autre endroit un jour). Ne faudrait-il mieux pas lire le contenu de ton plist de la manière symétrique à celle utilisée pour écrire le plist ?!
D'autant que je trouve que d'utiliser directement en dur le chemin du plist n'est pas très classe pour le coup, même si y'a pire et que ça passe encore, c'est pas la façon idéale d'accéder aux prefs...
Perso je préfère mettre un peu de texte avant et après le "%@" dans mes NSLogs pour bien voir d'une part de quel NSLog il s'agit, mais aussi pouvoir bien isoler le contenu à afficher.
Cela évite de pourir la pist com.apple.iPhoto.plist.
Encore merci à vous.