Home

Moving passwords.

Is there a way to migrate my %localappdata%\LINQPad\Passwords to a new laptop? Or backup this file in my 1Password?

I am not familiar with how DPAPI decrypts these passwords. I assume the key to them is somewhere I would not be able to migrate?

Comments

  • There is no export/import feature - you would have to write this yourself. If you want to go down this path, press Shift+Alt+R to bring up ILSpy, then take a look at LINQPad's PasswordManager class - this has the info you need.

  • edited October 17

    Having had to just do this myself, thought I'd post here.

    void Main()
    {
      Util.HtmlHead.AddStyles("table tr td:nth-child(2) { word-wrap: break-word; max-width: 1000px }");
    
      var userDataFiles = new DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "LINQPad", "UserData"))
          .Dump("UserData Folder Path")
          .EnumerateFiles()
          .OrderByDescending(x=>x.LastWriteTime);
    
      userDataFiles.Select(x => new {
            x.Name,
            Content = x.OpenText().Using(f =>
            {
                var str = new char[250];
                f.ReadBlock(str, 0, (int)Math.Min(f.BaseStream.Length, 250L));
                var sb = new StringBuilder().Append(new string(str).TrimEnd('\0'))
                                            .Append(f.BaseStream.Length > 250 ? "..." : string.Empty);
                return sb.ToString();
            }),
            LastWrite = x.LastWriteTime.Humanize(),
            File = new Hyperlink("Open", _ => Shortcuts.OpenNotepadPP(x.FullName))
      })
      .Dump("LoadString keys");
    
      new Button("Export User Data", _ => {
            new TextArea(JsonConvert.SerializeObject(userDataFiles.ToDictionary(df => df.Name, df => Convert.ToBase64String(df.ReadAllBytes())))).Dump();
      }).Dump();
    
      var passwords = new DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "LINQPad", "Passwords")).Dump("Passwords Folder Path")
        .EnumerateFiles()
        .OrderByDescending(x => x.LastWriteTime)
        .Select(x =>
        {
            var name = Encoding.UTF8.GetString(Enumerable.Range(0, x.Name.Length)
                                                         .Where(x => x % 2 == 0)
                                                         .Select(i => Convert.ToByte(x.Name.Substring(i, 2), 16))
                                                         .ToArray());
            return new {
                Name = name,
                LastWrite = x.LastWriteTime.Humanize(),
                Content = Util.OnDemand("Click to show", () => Util.GetPassword(name))
            };
        })
        .Dump("Passwords");
    
        new Button("Export Passwords", _ => {
            new TextArea(JsonConvert.SerializeObject(passwords.ToDictionary(df => df.Name, df => Convert.ToBase64String(Encoding.UTF8.GetBytes(Util.GetPassword(df.Name)))))).Dump();
        }).Dump();
    }
    
    public static class Shortcuts
    {
        static string Quote(string s) => s.Contains(" ") ? $"\"{s}\"" : s;
        public static void OpenNotepadPP(string f)
        {
            var progDir = Environment.GetEnvironmentVariable("ProgramFiles(x86)");
            var npDir = Path.Combine("Notepad++", "notepad++.exe");
            Util.Cmd($"{Quote(Path.Combine(progDir, npDir))} {Quote(f)}");
        }
        public static byte[] ReadAllBytes(this FileInfo f) => !f.Exists ? Array.Empty<byte>() : File.ReadAllBytes(f.FullName);
        public static TReturn? Using<TDisposable, TReturn>(this TDisposable disposable, Func<TDisposable, TReturn> workFunc) where TDisposable : IDisposable
        {
            using (disposable)
            {
                return workFunc(disposable);
            }
        }
    }
    

    and to import afterwards:

    const string LoadStringType = "Util.LoadString";
    const string PasswordType = "Util.Password";
    var importType = new SelectBox(SelectBoxKind.DropDown, new[] { LoadStringType, PasswordType }).Dump("Import type");
    var ta = new TextArea().Dump("Paste your json here");
    new Button("Import",_ => {
        var dict = JsonConvert.DeserializeObject<Dictionary<string,string>>(ta.Text);
        Action<string,string> importFunc = importType.SelectedOption switch {
            LoadStringType => (a,b) => Util.SaveString(a,b),
            PasswordType => (a,b) => Util.SetPassword(a,b)
        };
        foreach (var pair in dict)
        {
            Console.WriteLine("Saving string '{0}'", pair.Key);
            importFunc(pair.Key, Encoding.UTF8.GetString(Convert.FromBase64String(pair.Value)));
        }
    }).Dump();
    

    Export requires the Humanizer nuget package.Both use Newtonsoft.Json, obviously.

Sign In or Register to comment.