├── .gitattributes
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── Steam Desktop Authenticator
├── App.config
├── CaptchaForm.Designer.cs
├── CaptchaForm.cs
├── CaptchaForm.resx
├── CommandLineOptions.cs
├── ConfirmationButton.cs
├── ConfirmationFormWeb.Designer.cs
├── ConfirmationFormWeb.cs
├── ConfirmationFormWeb.resx
├── FileEncryptor.cs
├── ImportAccountForm.Designer.cs
├── ImportAccountForm.cs
├── ImportAccountForm.resx
├── InputForm.Designer.cs
├── InputForm.cs
├── InputForm.resx
├── ListInputForm.Designer.cs
├── ListInputForm.cs
├── ListInputForm.resx
├── LoginForm.Designer.cs
├── LoginForm.cs
├── LoginForm.resx
├── MaFileEncryptedException.cs
├── MainForm.Designer.cs
├── MainForm.cs
├── MainForm.resx
├── Manifest.cs
├── ManifestParseException.cs
├── PhoneInputForm.Designer.cs
├── PhoneInputForm.cs
├── PhoneInputForm.resx
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
├── SettingsForm.Designer.cs
├── SettingsForm.cs
├── SettingsForm.resx
├── Steam Desktop Authenticator.csproj
├── Steam Desktop Authenticator.sln
├── TradePopupForm.Designer.cs
├── TradePopupForm.cs
├── TradePopupForm.resx
├── UserFormAuthenticator.cs
├── WelcomeForm.Designer.cs
├── WelcomeForm.cs
├── WelcomeForm.resx
├── icon.ico
└── packages.config
└── icon.png
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # StyleCop
65 | StyleCopReport.xml
66 |
67 | # Files built by Visual Studio
68 | *_i.c
69 | *_p.c
70 | *_h.h
71 | *.ilk
72 | *.meta
73 | *.obj
74 | *.iobj
75 | *.pch
76 | *.pdb
77 | *.ipdb
78 | *.pgc
79 | *.pgd
80 | *.rsp
81 | *.sbr
82 | *.tlb
83 | *.tli
84 | *.tlh
85 | *.tmp
86 | *.tmp_proj
87 | *_wpftmp.csproj
88 | *.log
89 | *.vspscc
90 | *.vssscc
91 | .builds
92 | *.pidb
93 | *.svclog
94 | *.scc
95 |
96 | # Chutzpah Test files
97 | _Chutzpah*
98 |
99 | # Visual C++ cache files
100 | ipch/
101 | *.aps
102 | *.ncb
103 | *.opendb
104 | *.opensdf
105 | *.sdf
106 | *.cachefile
107 | *.VC.db
108 | *.VC.VC.opendb
109 |
110 | # Visual Studio profiler
111 | *.psess
112 | *.vsp
113 | *.vspx
114 | *.sap
115 |
116 | # Visual Studio Trace Files
117 | *.e2e
118 |
119 | # TFS 2012 Local Workspace
120 | $tf/
121 |
122 | # Guidance Automation Toolkit
123 | *.gpState
124 |
125 | # ReSharper is a .NET coding add-in
126 | _ReSharper*/
127 | *.[Rr]e[Ss]harper
128 | *.DotSettings.user
129 |
130 | # TeamCity is a build add-in
131 | _TeamCity*
132 |
133 | # DotCover is a Code Coverage Tool
134 | *.dotCover
135 |
136 | # AxoCover is a Code Coverage Tool
137 | .axoCover/*
138 | !.axoCover/settings.json
139 |
140 | # Coverlet is a free, cross platform Code Coverage Tool
141 | coverage*[.json, .xml, .info]
142 |
143 | # Visual Studio code coverage results
144 | *.coverage
145 | *.coveragexml
146 |
147 | # NCrunch
148 | _NCrunch_*
149 | .*crunch*.local.xml
150 | nCrunchTemp_*
151 |
152 | # MightyMoose
153 | *.mm.*
154 | AutoTest.Net/
155 |
156 | # Web workbench (sass)
157 | .sass-cache/
158 |
159 | # Installshield output folder
160 | [Ee]xpress/
161 |
162 | # DocProject is a documentation generator add-in
163 | DocProject/buildhelp/
164 | DocProject/Help/*.HxT
165 | DocProject/Help/*.HxC
166 | DocProject/Help/*.hhc
167 | DocProject/Help/*.hhk
168 | DocProject/Help/*.hhp
169 | DocProject/Help/Html2
170 | DocProject/Help/html
171 |
172 | # Click-Once directory
173 | publish/
174 |
175 | # Publish Web Output
176 | *.[Pp]ublish.xml
177 | *.azurePubxml
178 | # Note: Comment the next line if you want to checkin your web deploy settings,
179 | # but database connection strings (with potential passwords) will be unencrypted
180 | *.pubxml
181 | *.publishproj
182 |
183 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
184 | # checkin your Azure Web App publish settings, but sensitive information contained
185 | # in these scripts will be unencrypted
186 | PublishScripts/
187 |
188 | # NuGet Packages
189 | *.nupkg
190 | # NuGet Symbol Packages
191 | *.snupkg
192 | # The packages folder can be ignored because of Package Restore
193 | **/[Pp]ackages/*
194 | # except build/, which is used as an MSBuild target.
195 | !**/[Pp]ackages/build/
196 | # Uncomment if necessary however generally it will be regenerated when needed
197 | #!**/[Pp]ackages/repositories.config
198 | # NuGet v3's project.json files produces more ignorable files
199 | *.nuget.props
200 | *.nuget.targets
201 |
202 | # Microsoft Azure Build Output
203 | csx/
204 | *.build.csdef
205 |
206 | # Microsoft Azure Emulator
207 | ecf/
208 | rcf/
209 |
210 | # Windows Store app package directories and files
211 | AppPackages/
212 | BundleArtifacts/
213 | Package.StoreAssociation.xml
214 | _pkginfo.txt
215 | *.appx
216 | *.appxbundle
217 | *.appxupload
218 |
219 | # Visual Studio cache files
220 | # files ending in .cache can be ignored
221 | *.[Cc]ache
222 | # but keep track of directories ending in .cache
223 | !?*.[Cc]ache/
224 |
225 | # Others
226 | ClientBin/
227 | ~$*
228 | *~
229 | *.dbmdl
230 | *.dbproj.schemaview
231 | *.jfm
232 | *.pfx
233 | *.publishsettings
234 | orleans.codegen.cs
235 |
236 | # Including strong name files can present a security risk
237 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
238 | #*.snk
239 |
240 | # Since there are multiple workflows, uncomment next line to ignore bower_components
241 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
242 | #bower_components/
243 |
244 | # RIA/Silverlight projects
245 | Generated_Code/
246 |
247 | # Backup & report files from converting an old project file
248 | # to a newer Visual Studio version. Backup files are not needed,
249 | # because we have git ;-)
250 | _UpgradeReport_Files/
251 | Backup*/
252 | UpgradeLog*.XML
253 | UpgradeLog*.htm
254 | ServiceFabricBackup/
255 | *.rptproj.bak
256 |
257 | # SQL Server files
258 | *.mdf
259 | *.ldf
260 | *.ndf
261 |
262 | # Business Intelligence projects
263 | *.rdl.data
264 | *.bim.layout
265 | *.bim_*.settings
266 | *.rptproj.rsuser
267 | *- [Bb]ackup.rdl
268 | *- [Bb]ackup ([0-9]).rdl
269 | *- [Bb]ackup ([0-9][0-9]).rdl
270 |
271 | # Microsoft Fakes
272 | FakesAssemblies/
273 |
274 | # GhostDoc plugin setting file
275 | *.GhostDoc.xml
276 |
277 | # Node.js Tools for Visual Studio
278 | .ntvs_analysis.dat
279 | node_modules/
280 |
281 | # Visual Studio 6 build log
282 | *.plg
283 |
284 | # Visual Studio 6 workspace options file
285 | *.opt
286 |
287 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
288 | *.vbw
289 |
290 | # Visual Studio LightSwitch build output
291 | **/*.HTMLClient/GeneratedArtifacts
292 | **/*.DesktopClient/GeneratedArtifacts
293 | **/*.DesktopClient/ModelManifest.xml
294 | **/*.Server/GeneratedArtifacts
295 | **/*.Server/ModelManifest.xml
296 | _Pvt_Extensions
297 |
298 | # Paket dependency manager
299 | .paket/paket.exe
300 | paket-files/
301 |
302 | # FAKE - F# Make
303 | .fake/
304 |
305 | # CodeRush personal settings
306 | .cr/personal
307 |
308 | # Python Tools for Visual Studio (PTVS)
309 | __pycache__/
310 | *.pyc
311 |
312 | # Cake - Uncomment if you are using it
313 | # tools/**
314 | # !tools/packages.config
315 |
316 | # Tabs Studio
317 | *.tss
318 |
319 | # Telerik's JustMock configuration file
320 | *.jmconfig
321 |
322 | # BizTalk build output
323 | *.btp.cs
324 | *.btm.cs
325 | *.odx.cs
326 | *.xsd.cs
327 |
328 | # OpenCover UI analysis results
329 | OpenCover/
330 |
331 | # Azure Stream Analytics local run output
332 | ASALocalRun/
333 |
334 | # MSBuild Binary and Structured Log
335 | *.binlog
336 |
337 | # NVidia Nsight GPU debugger configuration file
338 | *.nvuser
339 |
340 | # MFractors (Xamarin productivity tool) working folder
341 | .mfractor/
342 |
343 | # Local History for Visual Studio
344 | .localhistory/
345 |
346 | # BeatPulse healthcheck temp database
347 | healthchecksdb
348 |
349 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
350 | MigrationBackup/
351 |
352 | # Ionide (cross platform F# VS Code tools) working folder
353 | .ionide/
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "lib/SteamAuth"]
2 | path = lib/SteamAuth
3 | url = https://github.com/geel9/SteamAuth
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Jesse Cardone
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Steam Desktop Authenticator
5 |
6 |
7 | A desktop implementation of Steam's mobile authenticator app.
8 | We are not affiliated with Steam or Scrap.TF in any way! This project is run by community volunteers.
9 |
10 |
11 | WARNING: Recently there have been fake versions of SDA floating around that will steal your Steam account. Never download SDA from any place other than this github repo!
12 |
13 |
16 | Supports Windows 7 and up.
17 |
18 |
19 |
20 | **DISCLAIMER: We provide no support for you when using Steam Desktop Authenticator! This project is run by community volunteers and is not affiliated with Steam or Scrap.TF. You use this program at your own risk, and accept the responsibility to make backups and prevent unauthorized access to your computer!**
21 |
22 | **REMEMBER: Always make backups of your `maFiles` directory! If you lose your encryption key or delete `maFiles` by accident AND you didn't save your revocation code, you are screwed.**
23 |
24 | **FINALLY: Using this application is a bad idea, because it COMPLETELY DEFEATS THE PURPOSE of two-factor authentication! If your desktop is infected with a virus, it will be able to hijack the authenticator app and completely subvert the protection. THIS APPLICATION DOES NOT PROTECT YOUR ACCOUNT; IT ONLY ALLOWS YOU TO USE STEAM FEATURES THAT REQUIRE THE AUTHENTICATOR WITHOUT HAVING A PHONE. If you have a phone that supports the Mobile Authenticator, you really shouldn't use this application!**
25 |
26 | IF you lost your `maFiles` OR lost your encryption key, go [here](https://store.steampowered.com/twofactor/manage) and click "Remove Authenticator" then enter your revocation code that you wrote down when you first added your account to SDA.
27 |
28 | If you did not follow the directions and did not write your revocation code down, you're well and truly screwed. The only option is beg to [Steam Support](https://support.steampowered.com/) and say you lost your mobile authenticator and the revocation code.
29 |
30 | ## Detailed setup instructions
31 | - Download & Install [.NET Framework 4.7.2](https://www.microsoft.com/net/download/dotnet-framework-runtime/net472) if you're using Windows 7. Windows 8 and above should do this automatically for you.
32 | - Visit [the releases page](https://github.com/SteamDesktopAuthenticatorr/SteamDesktopAuthenticator/releases) and download the latest .zip (not the source code one).
33 | - Extract the files somewhere very safe on your computer. If you lose the files you can lose access to your Steam account.
34 | - Run `Steam Desktop Authenticator.exe` and click the button to set up a new account.
35 | - Login to Steam and follow the instructions to set it up. **Note: you still need a mobile phone that can receive SMS.**
36 | - You may be asked to set up encryption, this is to make sure if someone gains access to your computer they can't steal your Steam account from this program. This is optional but highly recommended.
37 | - Select your account from the list to view the current login code, and click `Trade Confirmations` to see pending trade confirmations.
38 | - For your safety, remember to get Steam Guard backup codes! Follow [this link](https://store.steampowered.com/twofactor/manage) and click "Get Backup Codes," then print out that page and save it in a safe place. You can use these codes if you lose access to your authenticator.
39 |
40 | [How to update SDA.](https://github.com/SteamDesktopAuthenticatorr/SteamDesktopAuthenticator/wiki/Updating)
41 |
42 | [How to use SDA on multiple computers.](https://github.com/SteamDesktopAuthenticatorr/SteamDesktopAuthenticator/wiki/Using-SDA-on-multiple-computers)
43 |
44 |
45 | ## Command line options
46 | ```
47 | -k [encryption key]
48 | Set your encryption key when opened
49 | -s
50 | Auto-minimize to tray when opened
51 | ```
52 |
53 | ## Troubleshooting
54 | - **Trade confirmation list is just white or a blank screen**
55 | - First open the "Selected Account" menu, then click "Force session refresh". If it still doesn't work after that, open the "Selected Account" menu again, then click "Login again" and login to your Steam account.
56 |
57 | If your problem doesn't appear on the list or none of the solutions worked, submit an issue on the issue tracker. When posting logs in an issue, please upload it to some site like [Pastebin](http://www.pastebin.com).
58 |
59 | ## Building on linux
60 | - First, you will need to install the `mono` and `monodevelop` packages, usually available from your standard package repository.
61 | - Open monodevelop and select File -> Open. Navigate to the folder where you cloned this program to and open the file "Steam Desktop Authenticator/Steam Desktop Authenticator.sln"
62 | - If you initialized submodules correctly, you should see two tree hirarchies on the left side of the screen, one labeled **SteamDesktopAuthenticator** and the other **SteamAuth**. (If you didn't, an error will be displayed; go update them!) For both of them, select "Packages", right click on "Newtonsoft.Json", and click update. Remember to do this for **both SteamDesktopAuthenticator and SteamAuth**
63 | - Select Project->Active Configuration->Release (this will make this application run faster)
64 | - Select Build->Build All. The package should now build successfully.
65 | - The resulting executable and files will be in "Steam Desktop Authenticator/bin/Release"
66 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/CaptchaForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Steam_Desktop_Authenticator
2 | {
3 | partial class CaptchaForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CaptchaForm));
32 | this.labelText = new System.Windows.Forms.Label();
33 | this.txtBox = new System.Windows.Forms.TextBox();
34 | this.btnAccept = new System.Windows.Forms.Button();
35 | this.btnCancel = new System.Windows.Forms.Button();
36 | this.pictureBoxCaptcha = new System.Windows.Forms.PictureBox();
37 | ((System.ComponentModel.ISupportInitialize)(this.pictureBoxCaptcha)).BeginInit();
38 | this.SuspendLayout();
39 | //
40 | // labelText
41 | //
42 | this.labelText.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
43 | this.labelText.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
44 | this.labelText.ForeColor = System.Drawing.SystemColors.ControlText;
45 | this.labelText.Location = new System.Drawing.Point(-1, 14);
46 | this.labelText.Name = "labelText";
47 | this.labelText.Size = new System.Drawing.Size(233, 18);
48 | this.labelText.TabIndex = 0;
49 | this.labelText.Text = "Please enter the following captcha code:";
50 | this.labelText.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
51 | //
52 | // txtBox
53 | //
54 | this.txtBox.Font = new System.Drawing.Font("Segoe UI", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
55 | this.txtBox.Location = new System.Drawing.Point(12, 84);
56 | this.txtBox.Name = "txtBox";
57 | this.txtBox.Size = new System.Drawing.Size(206, 33);
58 | this.txtBox.TabIndex = 1;
59 | //
60 | // btnAccept
61 | //
62 | this.btnAccept.Location = new System.Drawing.Point(11, 123);
63 | this.btnAccept.Name = "btnAccept";
64 | this.btnAccept.Size = new System.Drawing.Size(98, 28);
65 | this.btnAccept.TabIndex = 2;
66 | this.btnAccept.Text = "Submit";
67 | this.btnAccept.UseVisualStyleBackColor = true;
68 | this.btnAccept.Click += new System.EventHandler(this.btnAccept_Click);
69 | //
70 | // btnCancel
71 | //
72 | this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
73 | this.btnCancel.Location = new System.Drawing.Point(120, 123);
74 | this.btnCancel.Name = "btnCancel";
75 | this.btnCancel.Size = new System.Drawing.Size(98, 28);
76 | this.btnCancel.TabIndex = 3;
77 | this.btnCancel.Text = "Cancel";
78 | this.btnCancel.UseVisualStyleBackColor = true;
79 | this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
80 | //
81 | // pictureBoxCaptcha
82 | //
83 | this.pictureBoxCaptcha.Location = new System.Drawing.Point(12, 37);
84 | this.pictureBoxCaptcha.Name = "pictureBoxCaptcha";
85 | this.pictureBoxCaptcha.Size = new System.Drawing.Size(206, 40);
86 | this.pictureBoxCaptcha.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
87 | this.pictureBoxCaptcha.TabIndex = 4;
88 | this.pictureBoxCaptcha.TabStop = false;
89 | //
90 | // CaptchaForm
91 | //
92 | this.AcceptButton = this.btnAccept;
93 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
94 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
95 | this.CancelButton = this.btnCancel;
96 | this.ClientSize = new System.Drawing.Size(232, 164);
97 | this.Controls.Add(this.pictureBoxCaptcha);
98 | this.Controls.Add(this.btnCancel);
99 | this.Controls.Add(this.btnAccept);
100 | this.Controls.Add(this.txtBox);
101 | this.Controls.Add(this.labelText);
102 | this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
103 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
104 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
105 | this.Name = "CaptchaForm";
106 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
107 | ((System.ComponentModel.ISupportInitialize)(this.pictureBoxCaptcha)).EndInit();
108 | this.ResumeLayout(false);
109 | this.PerformLayout();
110 |
111 | }
112 |
113 | #endregion
114 |
115 | private System.Windows.Forms.Label labelText;
116 | public System.Windows.Forms.TextBox txtBox;
117 | private System.Windows.Forms.Button btnAccept;
118 | private System.Windows.Forms.Button btnCancel;
119 | private System.Windows.Forms.PictureBox pictureBoxCaptcha;
120 | }
121 | }
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/CaptchaForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 |
11 | namespace Steam_Desktop_Authenticator
12 | {
13 | public partial class CaptchaForm : Form
14 | {
15 | public bool Canceled = false;
16 | public string CaptchaGID = "";
17 | public string CaptchaURL = "";
18 | public string CaptchaCode
19 | {
20 | get
21 | {
22 | return this.txtBox.Text;
23 | }
24 | }
25 |
26 | public CaptchaForm(string GID)
27 | {
28 | this.CaptchaGID = GID;
29 | this.CaptchaURL = "https://steamcommunity.com/public/captcha.php?gid=" + GID;
30 | InitializeComponent();
31 | this.pictureBoxCaptcha.Load(CaptchaURL);
32 | }
33 |
34 | private void btnAccept_Click(object sender, EventArgs e)
35 | {
36 | this.Canceled = false;
37 | this.Close();
38 | }
39 |
40 | private void btnCancel_Click(object sender, EventArgs e)
41 | {
42 | this.Canceled = true;
43 | this.Close();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/CommandLineOptions.cs:
--------------------------------------------------------------------------------
1 | using CommandLine;
2 | using CommandLine.Text;
3 |
4 | namespace Steam_Desktop_Authenticator
5 | {
6 | class CommandLineOptions
7 | {
8 | [Option('k', "encryption-key", Required = false,
9 | HelpText = "Encryption key for manifest")]
10 | public string EncryptionKey { get; set; }
11 |
12 | [Option('s', "silent", Required = false,
13 | HelpText = "Start minimized")]
14 | public bool Silent { get; set; }
15 |
16 | [ParserState]
17 | public IParserState LastParserState { get; set; }
18 |
19 | [HelpOption]
20 | public string GetUsage()
21 | {
22 | return HelpText.AutoBuild(this,
23 | (HelpText current) => HelpText.DefaultParsingErrorsHandler(this, current));
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/ConfirmationButton.cs:
--------------------------------------------------------------------------------
1 | using SteamAuth;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Windows.Forms;
8 |
9 | namespace Steam_Desktop_Authenticator
10 | {
11 | public class ConfirmationButton : Button
12 | {
13 | public Confirmation Confirmation { get; set; }
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/ConfirmationFormWeb.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Steam_Desktop_Authenticator
2 | {
3 | partial class ConfirmationFormWeb
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ConfirmationFormWeb));
32 | this.splitContainer1 = new System.Windows.Forms.SplitContainer();
33 | this.btnRefresh = new System.Windows.Forms.Button();
34 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
35 | this.splitContainer1.Panel1.SuspendLayout();
36 | this.splitContainer1.SuspendLayout();
37 | this.SuspendLayout();
38 | //
39 | // splitContainer1
40 | //
41 | this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
42 | this.splitContainer1.IsSplitterFixed = true;
43 | this.splitContainer1.Location = new System.Drawing.Point(0, 0);
44 | this.splitContainer1.Name = "splitContainer1";
45 | this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
46 | //
47 | // splitContainer1.Panel1
48 | //
49 | this.splitContainer1.Panel1.Controls.Add(this.btnRefresh);
50 | this.splitContainer1.Size = new System.Drawing.Size(431, 641);
51 | this.splitContainer1.SplitterDistance = 30;
52 | this.splitContainer1.SplitterWidth = 1;
53 | this.splitContainer1.TabIndex = 0;
54 | //
55 | // btnRefresh
56 | //
57 | this.btnRefresh.Dock = System.Windows.Forms.DockStyle.Fill;
58 | this.btnRefresh.Location = new System.Drawing.Point(0, 0);
59 | this.btnRefresh.Name = "btnRefresh";
60 | this.btnRefresh.Size = new System.Drawing.Size(431, 30);
61 | this.btnRefresh.TabIndex = 0;
62 | this.btnRefresh.Text = "Refresh";
63 | this.btnRefresh.UseVisualStyleBackColor = true;
64 | this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);
65 | //
66 | // ConfirmationFormWeb
67 | //
68 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
69 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
70 | this.ClientSize = new System.Drawing.Size(431, 641);
71 | this.Controls.Add(this.splitContainer1);
72 | this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
73 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
74 | this.Name = "ConfirmationFormWeb";
75 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
76 | this.Text = "Trade Confirmations";
77 | this.Shown += new System.EventHandler(this.ConfirmationFormWeb_Shown);
78 | this.splitContainer1.Panel1.ResumeLayout(false);
79 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
80 | this.splitContainer1.ResumeLayout(false);
81 | this.ResumeLayout(false);
82 |
83 | }
84 |
85 | #endregion
86 |
87 | private System.Windows.Forms.SplitContainer splitContainer1;
88 | private System.Windows.Forms.Button btnRefresh;
89 | }
90 | }
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/ConfirmationFormWeb.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 | using System.Threading.Tasks;
4 | using System.Windows.Forms;
5 | using SteamAuth;
6 | using System.Drawing.Drawing2D;
7 |
8 | namespace Steam_Desktop_Authenticator
9 | {
10 | public partial class ConfirmationFormWeb : Form
11 | {
12 | private SteamGuardAccount steamAccount;
13 |
14 | public ConfirmationFormWeb(SteamGuardAccount steamAccount)
15 | {
16 | InitializeComponent();
17 | this.steamAccount = steamAccount;
18 | this.Text = String.Format("Trade Confirmations - {0}", steamAccount.AccountName);
19 | }
20 | private async Task LoadData()
21 | {
22 | this.splitContainer1.Panel2.Controls.Clear();
23 |
24 | // Check for a valid refresh token first
25 | if (steamAccount.Session.IsRefreshTokenExpired())
26 | {
27 | MessageBox.Show("Your session has expired. Use the login again button under the selected account menu.", "Trade Confirmations", MessageBoxButtons.OK, MessageBoxIcon.Error);
28 | this.Close();
29 | return;
30 | }
31 |
32 | // Check for a valid access token, refresh it if needed
33 | if (steamAccount.Session.IsAccessTokenExpired())
34 | {
35 | try
36 | {
37 | await steamAccount.Session.RefreshAccessToken();
38 | }
39 | catch (Exception ex)
40 | {
41 | MessageBox.Show(ex.Message, "Steam Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
42 | this.Close();
43 | return;
44 | }
45 | }
46 |
47 | try
48 | {
49 | var confirmations = await steamAccount.FetchConfirmationsAsync();
50 |
51 | if (confirmations == null || confirmations.Length == 0)
52 | {
53 | Label errorLabel = new Label() { Text = "Nothing to confirm/cancel", AutoSize = true, ForeColor = Color.Black, Location = new Point(150, 20) };
54 | this.splitContainer1.Panel2.Controls.Add(errorLabel);
55 | }
56 |
57 | foreach (var confirmation in confirmations)
58 | {
59 | Panel panel = new Panel() { Dock = DockStyle.Top, Height = 120 };
60 | panel.Paint += (s, e) =>
61 | {
62 | using (LinearGradientBrush brush = new LinearGradientBrush(panel.ClientRectangle, Color.Black, Color.DarkCyan, 90F))
63 | {
64 | e.Graphics.FillRectangle(brush, panel.ClientRectangle);
65 | }
66 | };
67 |
68 | if (!string.IsNullOrEmpty(confirmation.Icon))
69 | {
70 | PictureBox pictureBox = new PictureBox() { Width = 60, Height = 60, Location = new Point(20, 20), SizeMode = PictureBoxSizeMode.Zoom };
71 | pictureBox.Load(confirmation.Icon);
72 | panel.Controls.Add(pictureBox);
73 | }
74 |
75 | Label nameLabel = new Label()
76 | {
77 | Text = $"{confirmation.Headline}\n{confirmation.Creator.ToString()}",
78 | AutoSize = true,
79 | ForeColor = Color.Snow,
80 | Location = new Point(90, 20),
81 | BackColor = Color.Transparent
82 | };
83 | panel.Controls.Add(nameLabel);
84 |
85 | ConfirmationButton acceptButton = new ConfirmationButton()
86 | {
87 | Text = confirmation.Accept,
88 | Location = new Point(90, 50),
89 | FlatStyle = FlatStyle.Flat,
90 | FlatAppearance = { BorderSize = 0 },
91 | BackColor = Color.Black,
92 | ForeColor = Color.Snow,
93 | Confirmation = confirmation
94 | };
95 | acceptButton.Click += btnAccept_Click;
96 | panel.Controls.Add(acceptButton);
97 |
98 | ConfirmationButton cancelButton = new ConfirmationButton()
99 | {
100 | Text = confirmation.Cancel,
101 | Location = new Point(180, 50),
102 | FlatStyle = FlatStyle.Flat,
103 | FlatAppearance = { BorderSize = 0 },
104 | BackColor = Color.Black,
105 | ForeColor = Color.Snow,
106 | Confirmation = confirmation
107 | };
108 | cancelButton.Click += btnCancel_Click;
109 | panel.Controls.Add(cancelButton);
110 |
111 | Label summaryLabel = new Label()
112 | {
113 | Text = String.Join("\n", confirmation.Summary),
114 | AutoSize = true,
115 | ForeColor = Color.Snow,
116 | Location = new Point(90, 80),
117 | BackColor = Color.Transparent
118 | };
119 | panel.Controls.Add(summaryLabel);
120 |
121 | this.splitContainer1.Panel2.Controls.Add(panel);
122 | }
123 | }
124 | catch (Exception ex)
125 | {
126 | Label errorLabel = new Label() { Text = "Something went wrong:\n" + ex.Message, AutoSize = true, ForeColor = Color.Red, Location = new Point(20, 20) };
127 | this.splitContainer1.Panel2.Controls.Add(errorLabel);
128 | }
129 | }
130 |
131 | private async void btnAccept_Click(object sender, EventArgs e)
132 | {
133 | var button = (ConfirmationButton)sender;
134 | var confirmation = button.Confirmation;
135 | bool result = await steamAccount.AcceptConfirmation(confirmation);
136 |
137 | await this.LoadData();
138 | }
139 |
140 | private async void btnCancel_Click(object sender, EventArgs e)
141 | {
142 | var button = (ConfirmationButton)sender;
143 | var confirmation = button.Confirmation;
144 | bool result = await steamAccount.DenyConfirmation(confirmation);
145 |
146 | await this.LoadData();
147 | }
148 |
149 |
150 | private async void btnRefresh_Click(object sender, EventArgs e)
151 | {
152 | this.btnRefresh.Enabled = false;
153 | this.btnRefresh.Text = "Refreshing...";
154 |
155 | await this.LoadData();
156 |
157 | this.btnRefresh.Enabled = true;
158 | this.btnRefresh.Text = "Refresh";
159 | }
160 |
161 | private async void ConfirmationFormWeb_Shown(object sender, EventArgs e)
162 | {
163 | this.btnRefresh.Enabled = false;
164 | this.btnRefresh.Text = "Refreshing...";
165 |
166 | await this.LoadData();
167 |
168 | this.btnRefresh.Enabled = true;
169 | this.btnRefresh.Text = "Refresh";
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/FileEncryptor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Security.Cryptography;
7 | using System.IO;
8 |
9 | namespace Steam_Desktop_Authenticator
10 | {
11 | ///
12 | /// This class provides the controls that will encrypt and decrypt the *.maFile files
13 | ///
14 | /// Passwords entered will be passed into 100k rounds of PBKDF2 (RFC2898) with a cryptographically random salt.
15 | /// The generated key will then be passed into AES-256 (RijndalManaged) which will encrypt the data
16 | /// in cypher block chaining (CBC) mode, and then write both the PBKDF2 salt and encrypted data onto the disk.
17 | ///
18 | public static class FileEncryptor
19 | {
20 | private const int PBKDF2_ITERATIONS = 50000; //Set to 50k to make program not unbearably slow. May increase in future.
21 | private const int SALT_LENGTH = 8;
22 | private const int KEY_SIZE_BYTES = 32;
23 | private const int IV_LENGTH = 16;
24 |
25 | ///
26 | /// Returns an 8-byte cryptographically random salt in base64 encoding
27 | ///
28 | ///
29 | public static string GetRandomSalt()
30 | {
31 | byte[] salt = new byte[SALT_LENGTH];
32 | using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
33 | {
34 | rng.GetBytes(salt);
35 | }
36 | return Convert.ToBase64String(salt);
37 | }
38 |
39 | ///
40 | /// Returns a 16-byte cryptographically random initialization vector (IV) in base64 encoding
41 | ///
42 | ///
43 | public static string GetInitializationVector()
44 | {
45 | byte[] IV = new byte[IV_LENGTH];
46 | using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
47 | {
48 | rng.GetBytes(IV);
49 | }
50 | return Convert.ToBase64String(IV);
51 | }
52 |
53 |
54 | ///
55 | /// Generates an encryption key derived using a password, a random salt, and specified number of rounds of PBKDF2
56 | ///
57 | /// TODO: pass in password via SecureString?
58 | ///
59 | ///
60 | ///
61 | ///
62 | private static byte[] GetEncryptionKey(string password, string salt)
63 | {
64 | if (string.IsNullOrEmpty(password))
65 | {
66 | throw new ArgumentException("Password is empty");
67 | }
68 | if (string.IsNullOrEmpty(salt))
69 | {
70 | throw new ArgumentException("Salt is empty");
71 | }
72 | using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, Convert.FromBase64String(salt), PBKDF2_ITERATIONS))
73 | {
74 | return pbkdf2.GetBytes(KEY_SIZE_BYTES);
75 | }
76 | }
77 |
78 | ///
79 | /// Tries to decrypt and return data given an encrypted base64 encoded string. Must use the same
80 | /// password, salt, IV, and ciphertext that was used during the original encryption of the data.
81 | ///
82 | ///
83 | ///
84 | /// Initialization Vector
85 | ///
86 | ///
87 | public static string DecryptData(string password, string passwordSalt, string IV, string encryptedData)
88 | {
89 | if (string.IsNullOrEmpty(password))
90 | {
91 | throw new ArgumentException("Password is empty");
92 | }
93 | if (string.IsNullOrEmpty(passwordSalt))
94 | {
95 | throw new ArgumentException("Salt is empty");
96 | }
97 | if (string.IsNullOrEmpty(IV))
98 | {
99 | throw new ArgumentException("Initialization Vector is empty");
100 | }
101 | if (string.IsNullOrEmpty(encryptedData))
102 | {
103 | throw new ArgumentException("Encrypted data is empty");
104 | }
105 |
106 | byte[] cipherText = Convert.FromBase64String(encryptedData);
107 | byte[] key = GetEncryptionKey(password, passwordSalt);
108 | string plaintext = null;
109 |
110 | using (RijndaelManaged aes256 = new RijndaelManaged())
111 | {
112 | aes256.IV = Convert.FromBase64String(IV);
113 | aes256.Key = key;
114 | aes256.Padding = PaddingMode.PKCS7;
115 | aes256.Mode = CipherMode.CBC;
116 |
117 | //create decryptor to perform the stream transform
118 | ICryptoTransform decryptor = aes256.CreateDecryptor(aes256.Key, aes256.IV);
119 |
120 | //wrap in a try since a bad password yields a bad key, which would throw an exception on decrypt
121 | try
122 | {
123 | using (MemoryStream msDecrypt = new MemoryStream(cipherText))
124 | {
125 | using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
126 | {
127 | using (StreamReader srDecrypt = new StreamReader(csDecrypt))
128 | {
129 | plaintext = srDecrypt.ReadToEnd();
130 | }
131 | }
132 | }
133 | }
134 | catch (CryptographicException)
135 | {
136 | plaintext = null;
137 | }
138 | }
139 | return plaintext;
140 | }
141 |
142 | ///
143 | /// Encrypts a string given a password, salt, and initialization vector, then returns result in base64 encoded string.
144 | ///
145 | /// To retrieve this data, you must decrypt with the same password, salt, IV, and cyphertext that was used during encryption
146 | ///
147 | ///
148 | ///
149 | ///
150 | ///
151 | ///
152 | public static string EncryptData(string password, string passwordSalt, string IV, string plaintext)
153 | {
154 | if (string.IsNullOrEmpty(password))
155 | {
156 | throw new ArgumentException("Password is empty");
157 | }
158 | if (string.IsNullOrEmpty(passwordSalt))
159 | {
160 | throw new ArgumentException("Salt is empty");
161 | }
162 | if (string.IsNullOrEmpty(IV))
163 | {
164 | throw new ArgumentException("Initialization Vector is empty");
165 | }
166 | if (string.IsNullOrEmpty(plaintext))
167 | {
168 | throw new ArgumentException("Plaintext data is empty");
169 | }
170 | byte[] key = GetEncryptionKey(password, passwordSalt);
171 | byte[] ciphertext;
172 |
173 | using (RijndaelManaged aes256 = new RijndaelManaged())
174 | {
175 | aes256.Key = key;
176 | aes256.IV = Convert.FromBase64String(IV);
177 | aes256.Padding = PaddingMode.PKCS7;
178 | aes256.Mode = CipherMode.CBC;
179 |
180 | ICryptoTransform encryptor = aes256.CreateEncryptor(aes256.Key, aes256.IV);
181 |
182 | using (MemoryStream msEncrypt = new MemoryStream())
183 | {
184 | using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
185 | {
186 | using (StreamWriter swEncypt = new StreamWriter(csEncrypt))
187 | {
188 | swEncypt.Write(plaintext);
189 | }
190 | ciphertext = msEncrypt.ToArray();
191 | }
192 | }
193 | }
194 | return Convert.ToBase64String(ciphertext);
195 | }
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/ImportAccountForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Steam_Desktop_Authenticator
2 | {
3 | partial class ImportAccountForm
4 | {
5 | #region Windows Form Designer generated code
6 |
7 | ///
8 | /// Required method for Designer support - do not modify
9 | /// the contents of this method with the code editor.
10 | ///
11 | private void InitializeComponent()
12 | {
13 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImportAccountForm));
14 | this.labelText = new System.Windows.Forms.Label();
15 | this.txtBox = new System.Windows.Forms.TextBox();
16 | this.btnImport = new System.Windows.Forms.Button();
17 | this.btnCancel = new System.Windows.Forms.Button();
18 | this.label1 = new System.Windows.Forms.Label();
19 | this.SuspendLayout();
20 | //
21 | // labelText
22 | //
23 | this.labelText.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
24 | this.labelText.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
25 | this.labelText.ForeColor = System.Drawing.SystemColors.ControlText;
26 | this.labelText.Location = new System.Drawing.Point(15, 14);
27 | this.labelText.Name = "labelText";
28 | this.labelText.Size = new System.Drawing.Size(317, 25);
29 | this.labelText.TabIndex = 0;
30 | this.labelText.Text = "Enter your encryption passkey if your .maFile is encrypted:";
31 | //
32 | // txtBox
33 | //
34 | this.txtBox.Font = new System.Drawing.Font("Segoe UI", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
35 | this.txtBox.Location = new System.Drawing.Point(15, 42);
36 | this.txtBox.Name = "txtBox";
37 | this.txtBox.Size = new System.Drawing.Size(307, 33);
38 | this.txtBox.TabIndex = 1;
39 | //
40 | // btnImport
41 | //
42 | this.btnImport.Location = new System.Drawing.Point(135, 131);
43 | this.btnImport.Name = "btnImport";
44 | this.btnImport.Size = new System.Drawing.Size(187, 28);
45 | this.btnImport.TabIndex = 3;
46 | this.btnImport.Text = "Select .maFile file to Import";
47 | this.btnImport.UseVisualStyleBackColor = true;
48 | this.btnImport.Click += new System.EventHandler(this.btnImport_Click);
49 | //
50 | // btnCancel
51 | //
52 | this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
53 | this.btnCancel.Location = new System.Drawing.Point(41, 131);
54 | this.btnCancel.Name = "btnCancel";
55 | this.btnCancel.Size = new System.Drawing.Size(88, 28);
56 | this.btnCancel.TabIndex = 4;
57 | this.btnCancel.Text = "Cancel";
58 | this.btnCancel.UseVisualStyleBackColor = true;
59 | this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
60 | //
61 | // label1
62 | //
63 | this.label1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
64 | this.label1.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
65 | this.label1.ForeColor = System.Drawing.SystemColors.ControlText;
66 | this.label1.Location = new System.Drawing.Point(15, 83);
67 | this.label1.Name = "label1";
68 | this.label1.Size = new System.Drawing.Size(307, 40);
69 | this.label1.TabIndex = 2;
70 | this.label1.Text = "If you import an encrypted .maFile, the manifest file must be next to it.";
71 | //
72 | // ImportAccountForm
73 | //
74 | this.AcceptButton = this.btnImport;
75 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
76 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
77 | this.CancelButton = this.btnCancel;
78 | this.ClientSize = new System.Drawing.Size(336, 171);
79 | this.Controls.Add(this.label1);
80 | this.Controls.Add(this.btnCancel);
81 | this.Controls.Add(this.btnImport);
82 | this.Controls.Add(this.txtBox);
83 | this.Controls.Add(this.labelText);
84 | this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
85 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
86 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
87 | this.MaximizeBox = false;
88 | this.Name = "ImportAccountForm";
89 | this.ShowInTaskbar = false;
90 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
91 | this.Text = "Import Account";
92 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Import_maFile_Form_FormClosing);
93 | this.ResumeLayout(false);
94 | this.PerformLayout();
95 |
96 | }
97 |
98 | #endregion
99 |
100 | private System.Windows.Forms.Label labelText;
101 | private System.Windows.Forms.TextBox txtBox;
102 | private System.Windows.Forms.Button btnImport;
103 | private System.Windows.Forms.Button btnCancel;
104 | private System.Windows.Forms.Label label1;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/ImportAccountForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 | using SteamAuth;
11 | using Newtonsoft.Json;
12 | using Newtonsoft.Json.Linq;
13 | using System.IO;
14 |
15 | namespace Steam_Desktop_Authenticator
16 | {
17 | public partial class ImportAccountForm : Form
18 | {
19 | private Manifest mManifest;
20 |
21 | public ImportAccountForm()
22 | {
23 | InitializeComponent();
24 | this.mManifest = Manifest.GetManifest();
25 | }
26 |
27 | private void btnImport_Click(object sender, EventArgs e)
28 | {
29 | // check if data already added is encripted
30 | #region check if data already added is encripted
31 | string ContiuneImport = "0";
32 |
33 | string ManifestFile = "maFiles/manifest.json";
34 | if (File.Exists(ManifestFile))
35 | {
36 | string AppManifestContents = File.ReadAllText(ManifestFile);
37 | AppManifest AppManifestData = JsonConvert.DeserializeObject(AppManifestContents);
38 | bool AppManifestData_encrypted = AppManifestData.Encrypted;
39 | if (AppManifestData_encrypted == true)
40 | {
41 | MessageBox.Show("You can't import an .maFile because the existing account in the app is encrypted.\nDecrypt it and try again.");
42 | this.Close();
43 | }
44 | else if (AppManifestData_encrypted == false)
45 | {
46 | ContiuneImport = "1";
47 | }
48 | else
49 | {
50 | MessageBox.Show("invalid value for variable 'encrypted' inside manifest.json");
51 | this.Close();
52 | }
53 | }
54 | else
55 | {
56 | MessageBox.Show("An Error occurred, Restart the program!");
57 | }
58 | #endregion
59 |
60 | // Continue
61 | #region Continue
62 | if (ContiuneImport == "1")
63 | {
64 | this.Close();
65 |
66 | // read EncriptionKey from imput box
67 | string ImportUsingEncriptionKey = txtBox.Text;
68 |
69 | // Open file browser > to select the file
70 | OpenFileDialog openFileDialog1 = new OpenFileDialog();
71 |
72 | // Set filter options and filter index.
73 | openFileDialog1.Filter = "maFiles (.maFile)|*.maFile|All Files (*.*)|*.*";
74 | openFileDialog1.FilterIndex = 1;
75 | openFileDialog1.Multiselect = false;
76 |
77 | // Call the ShowDialog method to show the dialog box.
78 | DialogResult userClickedOK = openFileDialog1.ShowDialog();
79 |
80 | // Process input if the user clicked OK.
81 | if (userClickedOK == DialogResult.OK)
82 | {
83 | // Open the selected file to read.
84 | System.IO.Stream fileStream = openFileDialog1.OpenFile();
85 | string fileContents = null;
86 |
87 | using (System.IO.StreamReader reader = new System.IO.StreamReader(fileStream))
88 | {
89 | fileContents = reader.ReadToEnd();
90 | }
91 | fileStream.Close();
92 |
93 | try
94 | {
95 | if (ImportUsingEncriptionKey == "")
96 | {
97 | // Import maFile
98 | //-------------------------------------------
99 | #region Import maFile
100 | SteamGuardAccount maFile = JsonConvert.DeserializeObject(fileContents);
101 |
102 | if (maFile.Session == null || maFile.Session.SteamID == 0 || maFile.Session.IsAccessTokenExpired())
103 | {
104 | // Have the user to relogin to steam to get a new session
105 | LoginForm loginForm = new LoginForm(LoginForm.LoginType.Import, maFile);
106 | loginForm.ShowDialog();
107 |
108 | if (loginForm.Session == null || loginForm.Session.SteamID == 0)
109 | {
110 | MessageBox.Show("Login failed. Try to import this account again.", "Account Import", MessageBoxButtons.OK, MessageBoxIcon.Error);
111 | return;
112 | }
113 |
114 | // Save new session to the maFile
115 | maFile.Session = loginForm.Session;
116 | }
117 |
118 | // Save account
119 | mManifest.SaveAccount(maFile, false);
120 | MessageBox.Show("Account Imported!", "Account Import", MessageBoxButtons.OK);
121 | #endregion
122 | }
123 | else
124 | {
125 | // Import Encripted maFile
126 | //-------------------------------------------
127 | #region Import Encripted maFile
128 | //Read manifest.json encryption_iv encryption_salt
129 | string ImportFileName_Found = "0";
130 | string Salt_Found = null;
131 | string IV_Found = null;
132 | string ReadManifestEx = "0";
133 |
134 | //No directory means no manifest file anyways.
135 | ImportManifest newImportManifest = new ImportManifest();
136 | newImportManifest.Encrypted = false;
137 | newImportManifest.Entries = new List();
138 |
139 | // extract folder path
140 | string fullPath = openFileDialog1.FileName;
141 | string fileName = openFileDialog1.SafeFileName;
142 | string path = fullPath.Replace(fileName, "");
143 |
144 | // extract fileName
145 | string ImportFileName = fullPath.Replace(path, "");
146 |
147 | string ImportManifestFile = path + "manifest.json";
148 |
149 |
150 | if (File.Exists(ImportManifestFile))
151 | {
152 | string ImportManifestContents = File.ReadAllText(ImportManifestFile);
153 |
154 |
155 | try
156 | {
157 | ImportManifest account = JsonConvert.DeserializeObject(ImportManifestContents);
158 | //bool Import_encrypted = account.Encrypted;
159 |
160 | List newEntries = new List();
161 |
162 | foreach (var entry in account.Entries)
163 | {
164 | string FileName = entry.Filename;
165 | string encryption_iv = entry.IV;
166 | string encryption_salt = entry.Salt;
167 |
168 | if (ImportFileName == FileName)
169 | {
170 | ImportFileName_Found = "1";
171 | IV_Found = entry.IV;
172 | Salt_Found = entry.Salt;
173 | }
174 | }
175 | }
176 | catch (Exception)
177 | {
178 | ReadManifestEx = "1";
179 | MessageBox.Show("Invalid content inside manifest.json!\nImport Failed.");
180 | }
181 |
182 |
183 | // DECRIPT & Import
184 | //--------------------
185 | #region DECRIPT & Import
186 | if (ReadManifestEx == "0")
187 | {
188 | if (ImportFileName_Found == "1" && Salt_Found != null && IV_Found != null)
189 | {
190 | string decryptedText = FileEncryptor.DecryptData(ImportUsingEncriptionKey, Salt_Found, IV_Found, fileContents);
191 |
192 | if (decryptedText == null)
193 | {
194 | MessageBox.Show("Decryption Failed.\nImport Failed.");
195 | }
196 | else
197 | {
198 | string fileText = decryptedText;
199 |
200 | SteamGuardAccount maFile = JsonConvert.DeserializeObject(fileText);
201 | if (maFile.Session == null || maFile.Session.SteamID == 0 || maFile.Session.IsAccessTokenExpired())
202 | {
203 | // Have the user to relogin to steam to get a new session
204 | LoginForm loginForm = new LoginForm(LoginForm.LoginType.Import, maFile);
205 | loginForm.ShowDialog();
206 |
207 | if (loginForm.Session == null || loginForm.Session.SteamID == 0)
208 | {
209 | MessageBox.Show("Login failed. Try to import this account again.", "Account Import", MessageBoxButtons.OK, MessageBoxIcon.Error);
210 | return;
211 | }
212 |
213 | // Save new session to the maFile
214 | maFile.Session = loginForm.Session;
215 | }
216 |
217 | // Save account
218 | mManifest.SaveAccount(maFile, false);
219 | MessageBox.Show("Account Imported!\nYour Account in now Decrypted!", "Account Import", MessageBoxButtons.OK);
220 | }
221 | }
222 | else
223 | {
224 | if (ImportFileName_Found == "0")
225 | {
226 | MessageBox.Show("Account not found inside manifest.json.\nImport Failed.");
227 | }
228 | else if (Salt_Found == null && IV_Found == null)
229 | {
230 | MessageBox.Show("manifest.json does not contain encrypted data.\nYour account may be unencrypted!\nImport Failed.");
231 | }
232 | else
233 | {
234 | if (IV_Found == null)
235 | {
236 | MessageBox.Show("manifest.json does not contain: encryption_iv\nImport Failed.");
237 | }
238 | else if (IV_Found == null)
239 | {
240 | MessageBox.Show("manifest.json does not contain: encryption_salt\nImport Failed.");
241 | }
242 | }
243 | }
244 | }
245 | #endregion //DECRIPT & Import END
246 |
247 |
248 | }
249 | else
250 | {
251 | MessageBox.Show("manifest.json is missing!\nImport Failed.");
252 | }
253 | #endregion //Import Encripted maFile END
254 | }
255 |
256 | }
257 | catch (Exception)
258 | {
259 | MessageBox.Show("This file is not a valid SteamAuth maFile.\nImport Failed.");
260 | }
261 | }
262 | }
263 | #endregion // Continue End
264 | }
265 |
266 | private void btnCancel_Click(object sender, EventArgs e)
267 | {
268 | this.Close();
269 | }
270 |
271 | private void Import_maFile_Form_FormClosing(object sender, FormClosingEventArgs e)
272 | {
273 | }
274 | }
275 |
276 |
277 | public class AppManifest
278 | {
279 | [JsonProperty("encrypted")]
280 | public bool Encrypted { get; set; }
281 | }
282 |
283 |
284 | public class ImportManifest
285 | {
286 | [JsonProperty("encrypted")]
287 | public bool Encrypted { get; set; }
288 |
289 | [JsonProperty("entries")]
290 | public List Entries { get; set; }
291 | }
292 |
293 | public class ImportManifestEntry
294 | {
295 | [JsonProperty("encryption_iv")]
296 | public string IV { get; set; }
297 |
298 | [JsonProperty("encryption_salt")]
299 | public string Salt { get; set; }
300 |
301 | [JsonProperty("filename")]
302 | public string Filename { get; set; }
303 |
304 | [JsonProperty("steamid")]
305 | public ulong SteamID { get; set; }
306 | }
307 | }
308 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/InputForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Steam_Desktop_Authenticator
2 | {
3 | partial class InputForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(InputForm));
32 | this.labelText = new System.Windows.Forms.Label();
33 | this.txtBox = new System.Windows.Forms.TextBox();
34 | this.btnAccept = new System.Windows.Forms.Button();
35 | this.btnCancel = new System.Windows.Forms.Button();
36 | this.SuspendLayout();
37 | //
38 | // labelText
39 | //
40 | this.labelText.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
41 | this.labelText.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
42 | this.labelText.ForeColor = System.Drawing.SystemColors.ControlText;
43 | this.labelText.Location = new System.Drawing.Point(12, 9);
44 | this.labelText.Name = "labelText";
45 | this.labelText.Size = new System.Drawing.Size(383, 159);
46 | this.labelText.TabIndex = 0;
47 | this.labelText.Text = "Sample Text~~~";
48 | //
49 | // txtBox
50 | //
51 | this.txtBox.Font = new System.Drawing.Font("Segoe UI", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
52 | this.txtBox.Location = new System.Drawing.Point(12, 171);
53 | this.txtBox.Name = "txtBox";
54 | this.txtBox.Size = new System.Drawing.Size(383, 33);
55 | this.txtBox.TabIndex = 1;
56 | //
57 | // btnAccept
58 | //
59 | this.btnAccept.Location = new System.Drawing.Point(15, 210);
60 | this.btnAccept.Name = "btnAccept";
61 | this.btnAccept.Size = new System.Drawing.Size(98, 28);
62 | this.btnAccept.TabIndex = 2;
63 | this.btnAccept.Text = "Accept";
64 | this.btnAccept.UseVisualStyleBackColor = true;
65 | this.btnAccept.Click += new System.EventHandler(this.btnAccept_Click);
66 | //
67 | // btnCancel
68 | //
69 | this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
70 | this.btnCancel.Location = new System.Drawing.Point(297, 210);
71 | this.btnCancel.Name = "btnCancel";
72 | this.btnCancel.Size = new System.Drawing.Size(98, 28);
73 | this.btnCancel.TabIndex = 3;
74 | this.btnCancel.Text = "Cancel";
75 | this.btnCancel.UseVisualStyleBackColor = true;
76 | this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
77 | //
78 | // InputForm
79 | //
80 | this.AcceptButton = this.btnAccept;
81 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
82 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
83 | this.CancelButton = this.btnCancel;
84 | this.ClientSize = new System.Drawing.Size(407, 250);
85 | this.Controls.Add(this.btnCancel);
86 | this.Controls.Add(this.btnAccept);
87 | this.Controls.Add(this.txtBox);
88 | this.Controls.Add(this.labelText);
89 | this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
90 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
91 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
92 | this.MaximizeBox = false;
93 | this.Name = "InputForm";
94 | this.ShowInTaskbar = false;
95 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
96 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.InputForm_FormClosing);
97 | this.ResumeLayout(false);
98 | this.PerformLayout();
99 |
100 | }
101 |
102 | #endregion
103 |
104 | private System.Windows.Forms.Label labelText;
105 | public System.Windows.Forms.TextBox txtBox;
106 | private System.Windows.Forms.Button btnAccept;
107 | private System.Windows.Forms.Button btnCancel;
108 | }
109 | }
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/InputForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 |
11 | namespace Steam_Desktop_Authenticator
12 | {
13 | public partial class InputForm : Form
14 | {
15 | public bool Canceled = false;
16 | private bool userClosed = true;
17 |
18 | public InputForm(string label, bool password = false)
19 | {
20 | InitializeComponent();
21 | this.labelText.Text = label;
22 |
23 | if (password)
24 | {
25 | this.txtBox.PasswordChar = '*';
26 | }
27 | }
28 |
29 | private void btnAccept_Click(object sender, EventArgs e)
30 | {
31 | if (string.IsNullOrEmpty(this.txtBox.Text))
32 | {
33 | this.Canceled = true;
34 | this.userClosed = false;
35 | this.Close();
36 | }
37 | else
38 | {
39 | this.Canceled = false;
40 | this.userClosed = false;
41 | this.Close();
42 | }
43 | }
44 |
45 | private void btnCancel_Click(object sender, EventArgs e)
46 | {
47 | this.Canceled = true;
48 | this.userClosed = false;
49 | this.Close();
50 | }
51 |
52 | private void InputForm_FormClosing(object sender, FormClosingEventArgs e)
53 | {
54 | if (this.userClosed)
55 | {
56 | // Set Canceled = true when the user hits the X button.
57 | this.Canceled = true;
58 | }
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/ListInputForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Steam_Desktop_Authenticator
2 | {
3 | partial class ListInputForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ListInputForm));
32 | this.lbItems = new System.Windows.Forms.ListBox();
33 | this.btnAccept = new System.Windows.Forms.Button();
34 | this.btnCancel = new System.Windows.Forms.Button();
35 | this.SuspendLayout();
36 | //
37 | // lbItems
38 | //
39 | this.lbItems.FormattingEnabled = true;
40 | this.lbItems.Location = new System.Drawing.Point(23, 63);
41 | this.lbItems.Name = "lbItems";
42 | this.lbItems.Size = new System.Drawing.Size(248, 82);
43 | this.lbItems.TabIndex = 0;
44 | //
45 | // btnAccept
46 | //
47 | this.btnAccept.Location = new System.Drawing.Point(277, 63);
48 | this.btnAccept.Name = "btnAccept";
49 | this.btnAccept.Size = new System.Drawing.Size(75, 23);
50 | this.btnAccept.TabIndex = 1;
51 | this.btnAccept.Text = "Accept";
52 | this.btnAccept.UseVisualStyleBackColor = true;
53 | this.btnAccept.Click += new System.EventHandler(this.btnAccept_Click);
54 | //
55 | // btnCancel
56 | //
57 | this.btnCancel.Location = new System.Drawing.Point(277, 122);
58 | this.btnCancel.Name = "btnCancel";
59 | this.btnCancel.Size = new System.Drawing.Size(75, 23);
60 | this.btnCancel.TabIndex = 2;
61 | this.btnCancel.Text = "Cancel";
62 | this.btnCancel.UseVisualStyleBackColor = true;
63 | this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
64 | //
65 | // ListInputForm
66 | //
67 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
68 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
69 | this.ClientSize = new System.Drawing.Size(372, 172);
70 | this.Controls.Add(this.btnCancel);
71 | this.Controls.Add(this.btnAccept);
72 | this.Controls.Add(this.lbItems);
73 | this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
74 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
75 | this.Name = "ListInputForm";
76 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
77 | this.Text = "Select one";
78 | this.Load += new System.EventHandler(this.ListInputForm_Load);
79 | this.ResumeLayout(false);
80 |
81 | }
82 |
83 | #endregion
84 |
85 | private System.Windows.Forms.ListBox lbItems;
86 | private System.Windows.Forms.Button btnAccept;
87 | private System.Windows.Forms.Button btnCancel;
88 | }
89 | }
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/ListInputForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 |
11 | namespace Steam_Desktop_Authenticator
12 | {
13 | public partial class ListInputForm : Form
14 | {
15 | public ListInputForm(List options)
16 | {
17 | Items = options;
18 | InitializeComponent();
19 | }
20 |
21 | public int SelectedIndex;
22 | List Items;
23 |
24 | private void ListInputForm_Load(object sender, EventArgs e)
25 | {
26 | foreach (var item in Items)
27 | {
28 | lbItems.Items.Add(item);
29 | }
30 | }
31 |
32 | private void btnAccept_Click(object sender, EventArgs e)
33 | {
34 | if (lbItems.SelectedIndex != -1)
35 | {
36 | SelectedIndex = lbItems.SelectedIndex;
37 | this.Close();
38 | }
39 | }
40 |
41 | private void btnCancel_Click(object sender, EventArgs e)
42 | {
43 | this.Close();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/LoginForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Steam_Desktop_Authenticator
2 | {
3 | partial class LoginForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(LoginForm));
32 | this.label1 = new System.Windows.Forms.Label();
33 | this.txtUsername = new System.Windows.Forms.TextBox();
34 | this.txtPassword = new System.Windows.Forms.TextBox();
35 | this.label2 = new System.Windows.Forms.Label();
36 | this.btnSteamLogin = new System.Windows.Forms.Button();
37 | this.labelLoginExplanation = new System.Windows.Forms.Label();
38 | this.SuspendLayout();
39 | //
40 | // label1
41 | //
42 | this.label1.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
43 | this.label1.ForeColor = System.Drawing.SystemColors.ControlText;
44 | this.label1.Location = new System.Drawing.Point(12, 30);
45 | this.label1.Name = "label1";
46 | this.label1.Size = new System.Drawing.Size(86, 25);
47 | this.label1.TabIndex = 0;
48 | this.label1.Text = "Username:";
49 | this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
50 | //
51 | // txtUsername
52 | //
53 | this.txtUsername.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
54 | this.txtUsername.Location = new System.Drawing.Point(101, 31);
55 | this.txtUsername.Name = "txtUsername";
56 | this.txtUsername.Size = new System.Drawing.Size(220, 25);
57 | this.txtUsername.TabIndex = 1;
58 | //
59 | // txtPassword
60 | //
61 | this.txtPassword.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
62 | this.txtPassword.Location = new System.Drawing.Point(101, 63);
63 | this.txtPassword.Name = "txtPassword";
64 | this.txtPassword.PasswordChar = '*';
65 | this.txtPassword.Size = new System.Drawing.Size(220, 25);
66 | this.txtPassword.TabIndex = 3;
67 | //
68 | // label2
69 | //
70 | this.label2.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
71 | this.label2.ForeColor = System.Drawing.SystemColors.ControlText;
72 | this.label2.Location = new System.Drawing.Point(12, 62);
73 | this.label2.Name = "label2";
74 | this.label2.Size = new System.Drawing.Size(83, 25);
75 | this.label2.TabIndex = 2;
76 | this.label2.Text = "Password:";
77 | this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
78 | //
79 | // btnSteamLogin
80 | //
81 | this.btnSteamLogin.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
82 | this.btnSteamLogin.Location = new System.Drawing.Point(224, 147);
83 | this.btnSteamLogin.Name = "btnSteamLogin";
84 | this.btnSteamLogin.Size = new System.Drawing.Size(110, 33);
85 | this.btnSteamLogin.TabIndex = 4;
86 | this.btnSteamLogin.Text = "Login";
87 | this.btnSteamLogin.UseVisualStyleBackColor = true;
88 | this.btnSteamLogin.Click += new System.EventHandler(this.btnSteamLogin_Click);
89 | //
90 | // labelLoginExplanation
91 | //
92 | this.labelLoginExplanation.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
93 | this.labelLoginExplanation.Location = new System.Drawing.Point(15, 98);
94 | this.labelLoginExplanation.Name = "labelLoginExplanation";
95 | this.labelLoginExplanation.Size = new System.Drawing.Size(306, 46);
96 | this.labelLoginExplanation.TabIndex = 5;
97 | this.labelLoginExplanation.Text = "This will activate Steam Desktop Authenticator on your Steam account. This requir" +
98 | "es a phone number that can receive SMS.";
99 | //
100 | // LoginForm
101 | //
102 | this.AcceptButton = this.btnSteamLogin;
103 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
104 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
105 | this.ClientSize = new System.Drawing.Size(346, 193);
106 | this.Controls.Add(this.labelLoginExplanation);
107 | this.Controls.Add(this.btnSteamLogin);
108 | this.Controls.Add(this.txtPassword);
109 | this.Controls.Add(this.label2);
110 | this.Controls.Add(this.txtUsername);
111 | this.Controls.Add(this.label1);
112 | this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
113 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
114 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
115 | this.ImeMode = System.Windows.Forms.ImeMode.On;
116 | this.MaximizeBox = false;
117 | this.Name = "LoginForm";
118 | this.ShowIcon = false;
119 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
120 | this.Text = "Steam Login";
121 | this.Load += new System.EventHandler(this.LoginForm_Load);
122 | this.ResumeLayout(false);
123 | this.PerformLayout();
124 |
125 | }
126 |
127 | #endregion
128 |
129 | private System.Windows.Forms.Label label1;
130 | private System.Windows.Forms.TextBox txtUsername;
131 | private System.Windows.Forms.TextBox txtPassword;
132 | private System.Windows.Forms.Label label2;
133 | private System.Windows.Forms.Button btnSteamLogin;
134 | private System.Windows.Forms.Label labelLoginExplanation;
135 | }
136 | }
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/LoginForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using System.Windows.Forms;
4 | using SteamAuth;
5 | using SteamKit2;
6 | using SteamKit2.Authentication;
7 | using SteamKit2.Internal;
8 |
9 | namespace Steam_Desktop_Authenticator
10 | {
11 | public partial class LoginForm : Form
12 | {
13 | public SteamGuardAccount account;
14 | public LoginType LoginReason;
15 | public SessionData Session;
16 |
17 | public LoginForm(LoginType loginReason = LoginType.Initial, SteamGuardAccount account = null)
18 | {
19 | InitializeComponent();
20 | this.LoginReason = loginReason;
21 | this.account = account;
22 |
23 | try
24 | {
25 | if (this.LoginReason != LoginType.Initial)
26 | {
27 | txtUsername.Text = account.AccountName;
28 | txtUsername.Enabled = false;
29 | }
30 |
31 | if (this.LoginReason == LoginType.Refresh)
32 | {
33 | labelLoginExplanation.Text = "Your Steam credentials have expired. For trade and market confirmations to work properly, please login again.";
34 | }
35 | else if (this.LoginReason == LoginType.Import)
36 | {
37 | labelLoginExplanation.Text = "Please login to your Steam account import it.";
38 | }
39 | }
40 | catch (Exception)
41 | {
42 | MessageBox.Show("Failed to find your account. Try closing and re-opening SDA.", "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
43 | this.Close();
44 | }
45 | }
46 |
47 | public void SetUsername(string username)
48 | {
49 | txtUsername.Text = username;
50 | }
51 |
52 | public string FilterPhoneNumber(string phoneNumber)
53 | {
54 | return phoneNumber.Replace("-", "").Replace("(", "").Replace(")", "");
55 | }
56 |
57 | public bool PhoneNumberOkay(string phoneNumber)
58 | {
59 | if (phoneNumber == null || phoneNumber.Length == 0) return false;
60 | if (phoneNumber[0] != '+') return false;
61 | return true;
62 | }
63 |
64 | private void ResetLoginButton()
65 | {
66 | btnSteamLogin.Enabled = true;
67 | btnSteamLogin.Text = "Login";
68 | }
69 |
70 | private async void btnSteamLogin_Click(object sender, EventArgs e)
71 | {
72 | // Disable button while we login
73 | btnSteamLogin.Enabled = false;
74 | btnSteamLogin.Text = "Logging in...";
75 |
76 | string username = txtUsername.Text;
77 | string password = txtPassword.Text;
78 |
79 | // Start a new SteamClient instance
80 | SteamClient steamClient = new SteamClient();
81 |
82 | // Connect to Steam
83 | steamClient.Connect();
84 |
85 | // Really basic way to wait until Steam is connected
86 | while (!steamClient.IsConnected)
87 | await Task.Delay(500);
88 |
89 | // Create a new auth session
90 | CredentialsAuthSession authSession;
91 | try
92 | {
93 | authSession = await steamClient.Authentication.BeginAuthSessionViaCredentialsAsync(new AuthSessionDetails
94 | {
95 | Username = username,
96 | Password = password,
97 | IsPersistentSession = false,
98 | PlatformType = EAuthTokenPlatformType.k_EAuthTokenPlatformType_MobileApp,
99 | ClientOSType = EOSType.Android9,
100 | Authenticator = new UserFormAuthenticator(this.account),
101 | });
102 | }
103 | catch (Exception ex)
104 | {
105 | MessageBox.Show(ex.Message, "Steam Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
106 | this.Close();
107 | return;
108 | }
109 |
110 | // Starting polling Steam for authentication response
111 | AuthPollResult pollResponse;
112 | try
113 | {
114 | pollResponse = await authSession.PollingWaitForResultAsync();
115 | }
116 | catch (Exception ex)
117 | {
118 | MessageBox.Show(ex.Message, "Steam Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
119 | this.Close();
120 | return;
121 | }
122 |
123 | // Build a SessionData object
124 | SessionData sessionData = new SessionData()
125 | {
126 | SteamID = authSession.SteamID.ConvertToUInt64(),
127 | AccessToken = pollResponse.AccessToken,
128 | RefreshToken = pollResponse.RefreshToken,
129 | };
130 |
131 | //Login succeeded
132 | this.Session = sessionData;
133 |
134 | // If we're only logging in for an account import, stop here
135 | if (LoginReason == LoginType.Import)
136 | {
137 | this.Close();
138 | return;
139 | }
140 |
141 | // If we're only logging in for a session refresh then save it and exit
142 | if (LoginReason == LoginType.Refresh)
143 | {
144 | Manifest man = Manifest.GetManifest();
145 | account.FullyEnrolled = true;
146 | account.Session = sessionData;
147 | HandleManifest(man, true);
148 | this.Close();
149 | return;
150 | }
151 |
152 | // Show a dialog to make sure they really want to add their authenticator
153 | var result = MessageBox.Show("Steam account login succeeded. Press OK to continue adding SDA as your authenticator.", "Steam Login", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
154 | if (result == DialogResult.Cancel)
155 | {
156 | MessageBox.Show("Adding authenticator aborted.", "Steam Login", MessageBoxButtons.OK, MessageBoxIcon.Error);
157 | ResetLoginButton();
158 | return;
159 | }
160 |
161 | // Begin linking mobile authenticator
162 | AuthenticatorLinker linker = new AuthenticatorLinker(sessionData);
163 |
164 | AuthenticatorLinker.LinkResult linkResponse = AuthenticatorLinker.LinkResult.GeneralFailure;
165 | while (linkResponse != AuthenticatorLinker.LinkResult.AwaitingFinalization)
166 | {
167 | try
168 | {
169 | linkResponse = await linker.AddAuthenticator();
170 | }
171 | catch (Exception ex)
172 | {
173 | MessageBox.Show("Error adding your authenticator: " + ex.Message, "Steam Login", MessageBoxButtons.OK, MessageBoxIcon.Error);
174 | ResetLoginButton();
175 | return;
176 | }
177 |
178 | switch (linkResponse)
179 | {
180 | case AuthenticatorLinker.LinkResult.MustProvidePhoneNumber:
181 |
182 | // Show the phone input form
183 | PhoneInputForm phoneInputForm = new PhoneInputForm(account);
184 | phoneInputForm.ShowDialog();
185 | if (phoneInputForm.Canceled)
186 | {
187 | this.Close();
188 | return;
189 | }
190 |
191 | linker.PhoneNumber = phoneInputForm.PhoneNumber;
192 | linker.PhoneCountryCode = phoneInputForm.CountryCode;
193 | break;
194 |
195 | case AuthenticatorLinker.LinkResult.AuthenticatorPresent:
196 | MessageBox.Show("This account already has an authenticator linked. You must remove that authenticator to add SDA as your authenticator.", "Steam Login", MessageBoxButtons.OK, MessageBoxIcon.Error);
197 | this.Close();
198 | return;
199 |
200 | case AuthenticatorLinker.LinkResult.FailureAddingPhone:
201 | MessageBox.Show("Failed to add your phone number. Please try again or use a different phone number.", "Steam Login", MessageBoxButtons.OK, MessageBoxIcon.Error);
202 | linker.PhoneNumber = null;
203 | break;
204 |
205 | case AuthenticatorLinker.LinkResult.MustRemovePhoneNumber:
206 | linker.PhoneNumber = null;
207 | break;
208 |
209 | case AuthenticatorLinker.LinkResult.MustConfirmEmail:
210 | MessageBox.Show("Please check your email, and click the link Steam sent you before continuing.", "Steam Login", MessageBoxButtons.OK, MessageBoxIcon.Information);
211 | break;
212 |
213 | case AuthenticatorLinker.LinkResult.GeneralFailure:
214 | MessageBox.Show("Error adding your authenticator.", "Steam Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
215 | this.Close();
216 | return;
217 | }
218 | } // End while loop checking for AwaitingFinalization
219 |
220 | Manifest manifest = Manifest.GetManifest();
221 | string passKey = null;
222 | if (manifest.Entries.Count == 0)
223 | {
224 | passKey = manifest.PromptSetupPassKey("Please enter an encryption passkey. Leave blank or hit cancel to not encrypt (VERY INSECURE).");
225 | }
226 | else if (manifest.Entries.Count > 0 && manifest.Encrypted)
227 | {
228 | bool passKeyValid = false;
229 | while (!passKeyValid)
230 | {
231 | InputForm passKeyForm = new InputForm("Please enter your current encryption passkey.");
232 | passKeyForm.ShowDialog();
233 | if (!passKeyForm.Canceled)
234 | {
235 | passKey = passKeyForm.txtBox.Text;
236 | passKeyValid = manifest.VerifyPasskey(passKey);
237 | if (!passKeyValid)
238 | {
239 | MessageBox.Show("That passkey is invalid. Please enter the same passkey you used for your other accounts.");
240 | }
241 | }
242 | else
243 | {
244 | this.Close();
245 | return;
246 | }
247 | }
248 | }
249 |
250 | //Save the file immediately; losing this would be bad.
251 | if (!manifest.SaveAccount(linker.LinkedAccount, passKey != null, passKey))
252 | {
253 | manifest.RemoveAccount(linker.LinkedAccount);
254 | MessageBox.Show("Unable to save mobile authenticator file. The mobile authenticator has not been linked.");
255 | this.Close();
256 | return;
257 | }
258 |
259 | MessageBox.Show("The Mobile Authenticator has not yet been linked. Before finalizing the authenticator, please write down your revocation code: " + linker.LinkedAccount.RevocationCode);
260 |
261 | AuthenticatorLinker.FinalizeResult finalizeResponse = AuthenticatorLinker.FinalizeResult.GeneralFailure;
262 | while (finalizeResponse != AuthenticatorLinker.FinalizeResult.Success)
263 | {
264 | InputForm smsCodeForm = new InputForm("Please input the SMS code sent to your phone.");
265 | smsCodeForm.ShowDialog();
266 | if (smsCodeForm.Canceled)
267 | {
268 | manifest.RemoveAccount(linker.LinkedAccount);
269 | this.Close();
270 | return;
271 | }
272 |
273 | InputForm confirmRevocationCode = new InputForm("Please enter your revocation code to ensure you've saved it.");
274 | confirmRevocationCode.ShowDialog();
275 | if (confirmRevocationCode.txtBox.Text.ToUpper() != linker.LinkedAccount.RevocationCode)
276 | {
277 | MessageBox.Show("Revocation code incorrect; the authenticator has not been linked.");
278 | manifest.RemoveAccount(linker.LinkedAccount);
279 | this.Close();
280 | return;
281 | }
282 |
283 | string smsCode = smsCodeForm.txtBox.Text;
284 | finalizeResponse = await linker.FinalizeAddAuthenticator(smsCode);
285 |
286 | switch (finalizeResponse)
287 | {
288 | case AuthenticatorLinker.FinalizeResult.BadSMSCode:
289 | continue;
290 |
291 | case AuthenticatorLinker.FinalizeResult.UnableToGenerateCorrectCodes:
292 | MessageBox.Show("Unable to generate the proper codes to finalize this authenticator. The authenticator should not have been linked. In the off-chance it was, please write down your revocation code, as this is the last chance to see it: " + linker.LinkedAccount.RevocationCode);
293 | manifest.RemoveAccount(linker.LinkedAccount);
294 | this.Close();
295 | return;
296 |
297 | case AuthenticatorLinker.FinalizeResult.GeneralFailure:
298 | MessageBox.Show("Unable to finalize this authenticator. The authenticator should not have been linked. In the off-chance it was, please write down your revocation code, as this is the last chance to see it: " + linker.LinkedAccount.RevocationCode);
299 | manifest.RemoveAccount(linker.LinkedAccount);
300 | this.Close();
301 | return;
302 | }
303 | }
304 |
305 | //Linked, finally. Re-save with FullyEnrolled property.
306 | manifest.SaveAccount(linker.LinkedAccount, passKey != null, passKey);
307 | MessageBox.Show("Mobile authenticator successfully linked. Please write down your revocation code: " + linker.LinkedAccount.RevocationCode);
308 | this.Close();
309 | }
310 |
311 | private void HandleManifest(Manifest man, bool IsRefreshing = false)
312 | {
313 | string passKey = null;
314 | if (man.Entries.Count == 0)
315 | {
316 | passKey = man.PromptSetupPassKey("Please enter an encryption passkey. Leave blank or hit cancel to not encrypt (VERY INSECURE).");
317 | }
318 | else if (man.Entries.Count > 0 && man.Encrypted)
319 | {
320 | bool passKeyValid = false;
321 | while (!passKeyValid)
322 | {
323 | InputForm passKeyForm = new InputForm("Please enter your current encryption passkey.");
324 | passKeyForm.ShowDialog();
325 | if (!passKeyForm.Canceled)
326 | {
327 | passKey = passKeyForm.txtBox.Text;
328 | passKeyValid = man.VerifyPasskey(passKey);
329 | if (!passKeyValid)
330 | {
331 | MessageBox.Show("That passkey is invalid. Please enter the same passkey you used for your other accounts.", "Steam Login", MessageBoxButtons.OK, MessageBoxIcon.Error);
332 | }
333 | }
334 | else
335 | {
336 | this.Close();
337 | return;
338 | }
339 | }
340 | }
341 |
342 | man.SaveAccount(account, passKey != null, passKey);
343 | if (IsRefreshing)
344 | {
345 | MessageBox.Show("Your session was refreshed.", "Steam Login", MessageBoxButtons.OK, MessageBoxIcon.Information);
346 | }
347 | else
348 | {
349 | MessageBox.Show("Mobile authenticator successfully linked. Please write down your revocation code: " + account.RevocationCode, "Steam Login", MessageBoxButtons.OK);
350 | }
351 | this.Close();
352 | }
353 |
354 | private void LoginForm_Load(object sender, EventArgs e)
355 | {
356 | if (account != null && account.AccountName != null)
357 | {
358 | txtUsername.Text = account.AccountName;
359 | }
360 | }
361 |
362 | public enum LoginType
363 | {
364 | Initial,
365 | Refresh,
366 | Import
367 | }
368 | }
369 | }
370 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/MaFileEncryptedException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Steam_Desktop_Authenticator
8 | {
9 | class MaFileEncryptedException : Exception
10 | {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/MainForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Windows.Forms;
4 | using SteamAuth;
5 | using System.Collections.Generic;
6 | using System.Text.RegularExpressions;
7 | using System.Net;
8 | using Newtonsoft.Json;
9 | using System.Threading;
10 | using System.Drawing;
11 | using System.Linq;
12 |
13 | namespace Steam_Desktop_Authenticator
14 | {
15 | public partial class MainForm : Form
16 | {
17 | private SteamGuardAccount currentAccount = null;
18 | private SteamGuardAccount[] allAccounts;
19 | private List updatedSessions = new List();
20 | private Manifest manifest;
21 | private static SemaphoreSlim confirmationsSemaphore = new SemaphoreSlim(1, 1);
22 |
23 | private long steamTime = 0;
24 | private long currentSteamChunk = 0;
25 | private string passKey = null;
26 | private bool startSilent = false;
27 |
28 | // Forms
29 | private TradePopupForm popupFrm = new TradePopupForm();
30 |
31 | public MainForm()
32 | {
33 | InitializeComponent();
34 | }
35 |
36 | public void SetEncryptionKey(string key)
37 | {
38 | passKey = key;
39 | }
40 |
41 | public void StartSilent(bool silent)
42 | {
43 | startSilent = silent;
44 | }
45 |
46 | // Form event handlers
47 |
48 | private void MainForm_Shown(object sender, EventArgs e)
49 | {
50 | this.labelVersion.Text = String.Format("v{0}", Application.ProductVersion);
51 | try
52 | {
53 | this.manifest = Manifest.GetManifest();
54 | }
55 | catch (ManifestParseException)
56 | {
57 | MessageBox.Show("Unable to read your settings. Try restating SDA.", "Steam Desktop Authenticator", MessageBoxButtons.OK, MessageBoxIcon.Error);
58 | this.Close();
59 | }
60 |
61 | // Make sure we don't show that welcome dialog again
62 | this.manifest.FirstRun = false;
63 | this.manifest.Save();
64 |
65 | // Tick first time manually to sync time
66 | timerSteamGuard_Tick(new object(), EventArgs.Empty);
67 |
68 | if (manifest.Encrypted)
69 | {
70 | if (passKey == null)
71 | {
72 | passKey = manifest.PromptForPassKey();
73 | if (passKey == null)
74 | {
75 | Application.Exit();
76 | }
77 | }
78 |
79 | btnManageEncryption.Text = "Manage Encryption";
80 | }
81 | else
82 | {
83 | btnManageEncryption.Text = "Setup Encryption";
84 | }
85 |
86 | btnManageEncryption.Enabled = manifest.Entries.Count > 0;
87 |
88 | loadSettings();
89 | loadAccountsList();
90 |
91 | checkForUpdates();
92 |
93 | if (startSilent)
94 | {
95 | this.WindowState = FormWindowState.Minimized;
96 | }
97 | }
98 |
99 | private void MainForm_Load(object sender, EventArgs e)
100 | {
101 | trayIcon.Icon = this.Icon;
102 | }
103 |
104 | private void MainForm_Resize(object sender, EventArgs e)
105 | {
106 | if (this.WindowState == FormWindowState.Minimized)
107 | {
108 | this.Hide();
109 | }
110 | }
111 |
112 | private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
113 | {
114 | Application.Exit();
115 | }
116 |
117 |
118 | // UI Button handlers
119 |
120 | private void btnSteamLogin_Click(object sender, EventArgs e)
121 | {
122 | var loginForm = new LoginForm();
123 | loginForm.ShowDialog();
124 | this.loadAccountsList();
125 | }
126 |
127 | private void btnTradeConfirmations_Click(object sender, EventArgs e)
128 | {
129 | if (currentAccount == null) return;
130 |
131 | string oText = btnTradeConfirmations.Text;
132 | btnTradeConfirmations.Text = "Loading...";
133 | btnTradeConfirmations.Text = oText;
134 |
135 | ConfirmationFormWeb confirms = new ConfirmationFormWeb(currentAccount);
136 | confirms.Show();
137 | }
138 |
139 | private void btnManageEncryption_Click(object sender, EventArgs e)
140 | {
141 | if (manifest.Encrypted)
142 | {
143 | InputForm currentPassKeyForm = new InputForm("Enter current passkey", true);
144 | currentPassKeyForm.ShowDialog();
145 |
146 | if (currentPassKeyForm.Canceled)
147 | {
148 | return;
149 | }
150 |
151 | string curPassKey = currentPassKeyForm.txtBox.Text;
152 |
153 | InputForm changePassKeyForm = new InputForm("Enter new passkey, or leave blank to remove encryption.");
154 | changePassKeyForm.ShowDialog();
155 |
156 | if (changePassKeyForm.Canceled && !string.IsNullOrEmpty(changePassKeyForm.txtBox.Text))
157 | {
158 | return;
159 | }
160 |
161 | InputForm changePassKeyForm2 = new InputForm("Confirm new passkey, or leave blank to remove encryption.");
162 | changePassKeyForm2.ShowDialog();
163 |
164 | if (changePassKeyForm2.Canceled && !string.IsNullOrEmpty(changePassKeyForm.txtBox.Text))
165 | {
166 | return;
167 | }
168 |
169 | string newPassKey = changePassKeyForm.txtBox.Text;
170 | string confirmPassKey = changePassKeyForm2.txtBox.Text;
171 |
172 | if (newPassKey != confirmPassKey)
173 | {
174 | MessageBox.Show("Passkeys do not match.");
175 | return;
176 | }
177 |
178 | if (newPassKey.Length == 0)
179 | {
180 | newPassKey = null;
181 | }
182 |
183 | string action = newPassKey == null ? "remove" : "change";
184 | if (!manifest.ChangeEncryptionKey(curPassKey, newPassKey))
185 | {
186 | MessageBox.Show("Unable to " + action + " passkey.");
187 | }
188 | else
189 | {
190 | MessageBox.Show("Passkey successfully " + action + "d.");
191 | this.loadAccountsList();
192 | }
193 | }
194 | else
195 | {
196 | passKey = manifest.PromptSetupPassKey();
197 | this.loadAccountsList();
198 | }
199 | }
200 |
201 | private void labelUpdate_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
202 | {
203 | if (newVersion == null || currentVersion == null)
204 | {
205 | checkForUpdates();
206 | }
207 | else
208 | {
209 | compareVersions();
210 | }
211 | }
212 |
213 | private void btnCopy_Click(object sender, EventArgs e)
214 | {
215 | CopyLoginToken();
216 | }
217 |
218 |
219 | // Tool strip menu handlers
220 |
221 | private void menuQuit_Click(object sender, EventArgs e)
222 | {
223 | Application.Exit();
224 | }
225 |
226 | private void menuRemoveAccountFromManifest_Click(object sender, EventArgs e)
227 | {
228 | if (manifest.Encrypted)
229 | {
230 | MessageBox.Show("You cannot remove accounts from the manifest file while it is encrypted.", "Remove from manifest", MessageBoxButtons.OK, MessageBoxIcon.Error);
231 | }
232 | else
233 | {
234 | DialogResult res = MessageBox.Show("This will remove the selected account from the manifest file.\nUse this to move a maFile to another computer.\nThis will NOT delete your maFile.", "Remove from manifest", MessageBoxButtons.OKCancel);
235 | if (res == DialogResult.OK)
236 | {
237 | manifest.RemoveAccount(currentAccount, false);
238 | MessageBox.Show("Account removed from manifest.\nYou can now move its maFile to another computer and import it using the File menu.", "Remove from manifest");
239 | loadAccountsList();
240 | }
241 | }
242 | }
243 |
244 | private void menuLoginAgain_Click(object sender, EventArgs e)
245 | {
246 | this.PromptRefreshLogin(currentAccount);
247 | }
248 |
249 | private void menuImportAccount_Click(object sender, EventArgs e)
250 | {
251 | ImportAccountForm currentImport_maFile_Form = new ImportAccountForm();
252 | currentImport_maFile_Form.ShowDialog();
253 | loadAccountsList();
254 | }
255 |
256 | private void menuSettings_Click(object sender, EventArgs e)
257 | {
258 | new SettingsForm().ShowDialog();
259 | manifest = Manifest.GetManifest(true);
260 | loadSettings();
261 | }
262 |
263 | private async void menuDeactivateAuthenticator_Click(object sender, EventArgs e)
264 | {
265 | if (currentAccount == null) return;
266 |
267 | // Check for a valid refresh token first
268 | if (currentAccount.Session.IsRefreshTokenExpired())
269 | {
270 | MessageBox.Show("Your session has expired. Use the login again button under the selected account menu.", "Deactivate Authenticator", MessageBoxButtons.OK, MessageBoxIcon.Error);
271 | return;
272 | }
273 |
274 | // Check for a valid access token, refresh it if needed
275 | if (currentAccount.Session.IsAccessTokenExpired())
276 | {
277 | try
278 | {
279 | await currentAccount.Session.RefreshAccessToken();
280 | }
281 | catch (Exception ex)
282 | {
283 | MessageBox.Show(ex.Message, "Deactivate Authenticator Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
284 | return;
285 | }
286 | }
287 |
288 | DialogResult res = MessageBox.Show("Would you like to remove Steam Guard completely?\nYes - Remove Steam Guard completely.\nNo - Switch back to Email authentication.", "Deactivate Authenticator: " + currentAccount.AccountName, MessageBoxButtons.YesNoCancel);
289 | int scheme = 0;
290 | if (res == DialogResult.Yes)
291 | {
292 | scheme = 2;
293 | }
294 | else if (res == DialogResult.No)
295 | {
296 | scheme = 1;
297 | }
298 | else if (res == DialogResult.Cancel)
299 | {
300 | scheme = 0;
301 | }
302 |
303 | if (scheme != 0)
304 | {
305 | string confCode = currentAccount.GenerateSteamGuardCode();
306 | InputForm confirmationDialog = new InputForm(String.Format("Removing Steam Guard from {0}. Enter this confirmation code: {1}", currentAccount.AccountName, confCode));
307 | confirmationDialog.ShowDialog();
308 |
309 | if (confirmationDialog.Canceled)
310 | {
311 | return;
312 | }
313 |
314 | string enteredCode = confirmationDialog.txtBox.Text.ToUpper();
315 | if (enteredCode != confCode)
316 | {
317 | MessageBox.Show("Confirmation codes do not match. Steam Guard not removed.");
318 | return;
319 | }
320 |
321 | bool success = await currentAccount.DeactivateAuthenticator(scheme);
322 | if (success)
323 | {
324 | MessageBox.Show(String.Format("Steam Guard {0}. maFile will be deleted after hitting okay. If you need to make a backup, now's the time.", (scheme == 2 ? "removed completely" : "switched to emails")));
325 | this.manifest.RemoveAccount(currentAccount);
326 | this.loadAccountsList();
327 | }
328 | else
329 | {
330 | MessageBox.Show("Steam Guard failed to deactivate.");
331 | }
332 | }
333 | else
334 | {
335 | MessageBox.Show("Steam Guard was not removed. No action was taken.");
336 | }
337 | }
338 |
339 | // Tray menu handlers
340 | private void trayIcon_MouseDoubleClick(object sender, MouseEventArgs e)
341 | {
342 | trayRestore_Click(sender, EventArgs.Empty);
343 | }
344 |
345 | private void trayRestore_Click(object sender, EventArgs e)
346 | {
347 | this.Show();
348 | this.WindowState = FormWindowState.Normal;
349 | }
350 |
351 | private void trayQuit_Click(object sender, EventArgs e)
352 | {
353 | Application.Exit();
354 | }
355 |
356 | private void trayTradeConfirmations_Click(object sender, EventArgs e)
357 | {
358 | btnTradeConfirmations_Click(sender, e);
359 | }
360 |
361 | private void trayCopySteamGuard_Click(object sender, EventArgs e)
362 | {
363 | if (txtLoginToken.Text != "")
364 | {
365 | Clipboard.SetText(txtLoginToken.Text);
366 | }
367 | }
368 |
369 | private void trayAccountList_SelectedIndexChanged(object sender, EventArgs e)
370 | {
371 | listAccounts.SelectedIndex = trayAccountList.SelectedIndex;
372 | }
373 |
374 |
375 | // Misc UI handlers
376 | private void listAccounts_SelectedValueChanged(object sender, EventArgs e)
377 | {
378 | for (int i = 0; i < allAccounts.Length; i++)
379 | {
380 | // Check if index is out of bounds first
381 | if (i < 0 || listAccounts.SelectedIndex < 0)
382 | continue;
383 |
384 | SteamGuardAccount account = allAccounts[i];
385 | if (account.AccountName == (string)listAccounts.Items[listAccounts.SelectedIndex])
386 | {
387 | trayAccountList.Text = account.AccountName;
388 | currentAccount = account;
389 | loadAccountInfo();
390 | break;
391 | }
392 | }
393 | }
394 |
395 | private void txtAccSearch_TextChanged(object sender, EventArgs e)
396 | {
397 | List names = new List(getAllNames());
398 | names = names.FindAll(new Predicate(IsFilter));
399 |
400 | listAccounts.Items.Clear();
401 | listAccounts.Items.AddRange(names.ToArray());
402 |
403 | trayAccountList.Items.Clear();
404 | trayAccountList.Items.AddRange(names.ToArray());
405 | }
406 |
407 |
408 | // Timers
409 |
410 | private async void timerSteamGuard_Tick(object sender, EventArgs e)
411 | {
412 | lblStatus.Text = "Aligning time with Steam...";
413 | steamTime = await TimeAligner.GetSteamTimeAsync();
414 | lblStatus.Text = "";
415 |
416 | currentSteamChunk = steamTime / 30L;
417 | int secondsUntilChange = (int)(steamTime - (currentSteamChunk * 30L));
418 |
419 | loadAccountInfo();
420 | if (currentAccount != null)
421 | {
422 | pbTimeout.Value = 30 - secondsUntilChange;
423 | }
424 | }
425 |
426 | private async void timerTradesPopup_Tick(object sender, EventArgs e)
427 | {
428 | if (currentAccount == null || popupFrm.Visible) return;
429 | if (!confirmationsSemaphore.Wait(0))
430 | {
431 | return; //Only one thread may access this critical section at once. Mutex is a bad choice here because it'll cause a pileup of threads.
432 | }
433 |
434 | List confs = new List();
435 | Dictionary> autoAcceptConfirmations = new Dictionary>();
436 |
437 | SteamGuardAccount[] accs =
438 | manifest.CheckAllAccounts ? allAccounts : new SteamGuardAccount[] { currentAccount };
439 |
440 | try
441 | {
442 | lblStatus.Text = "Checking confirmations...";
443 |
444 | foreach (var acc in accs)
445 | {
446 | // Check for a valid refresh token first
447 | if (acc.Session.IsRefreshTokenExpired())
448 | {
449 | MessageBox.Show("Your session for account " + acc.AccountName + " has expired. You will be prompted to login again.", "Trade Confirmations", MessageBoxButtons.OK, MessageBoxIcon.Error);
450 | PromptRefreshLogin(acc);
451 | break;
452 | }
453 |
454 | // Check for a valid access token, refresh it if needed
455 | if (acc.Session.IsAccessTokenExpired())
456 | {
457 | try
458 | {
459 | lblStatus.Text = "Refreshing session...";
460 | await acc.Session.RefreshAccessToken();
461 | lblStatus.Text = "Checking confirmations...";
462 | }
463 | catch (Exception ex)
464 | {
465 | MessageBox.Show(ex.Message, "Steam Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
466 | break;
467 | }
468 | }
469 |
470 | try
471 | {
472 | Confirmation[] tmp = await acc.FetchConfirmationsAsync();
473 | foreach (var conf in tmp)
474 | {
475 | if ((conf.ConfType == Confirmation.EMobileConfirmationType.MarketListing && manifest.AutoConfirmMarketTransactions) ||
476 | (conf.ConfType == Confirmation.EMobileConfirmationType.Trade && manifest.AutoConfirmTrades))
477 | {
478 | if (!autoAcceptConfirmations.ContainsKey(acc))
479 | autoAcceptConfirmations[acc] = new List();
480 | autoAcceptConfirmations[acc].Add(conf);
481 | }
482 | else
483 | confs.Add(conf);
484 | }
485 | }
486 | catch (Exception)
487 | {
488 |
489 | }
490 | }
491 |
492 | lblStatus.Text = "";
493 |
494 | if (confs.Count > 0)
495 | {
496 | popupFrm.Confirmations = confs.ToArray();
497 | popupFrm.Popup();
498 | }
499 | if (autoAcceptConfirmations.Count > 0)
500 | {
501 | foreach (var acc in autoAcceptConfirmations.Keys)
502 | {
503 | var confirmations = autoAcceptConfirmations[acc].ToArray();
504 | await acc.AcceptMultipleConfirmations(confirmations);
505 | }
506 | }
507 | }
508 | catch (SteamGuardAccount.WGTokenInvalidException)
509 | {
510 | lblStatus.Text = "";
511 | }
512 |
513 | confirmationsSemaphore.Release();
514 | }
515 |
516 | // Other methods
517 |
518 | private void CopyLoginToken()
519 | {
520 | string text = txtLoginToken.Text;
521 | if (String.IsNullOrEmpty(text))
522 | return;
523 | Clipboard.SetText(text);
524 | }
525 |
526 | ///
527 | /// Display a login form to the user to refresh their OAuth Token
528 | ///
529 | /// The account to refresh
530 | private void PromptRefreshLogin(SteamGuardAccount account)
531 | {
532 | var loginForm = new LoginForm(LoginForm.LoginType.Refresh, account);
533 | loginForm.ShowDialog();
534 | }
535 |
536 | ///
537 | /// Load UI with the current account info, this is run every second
538 | ///
539 | private void loadAccountInfo()
540 | {
541 | if (currentAccount != null && steamTime != 0)
542 | {
543 | popupFrm.Account = currentAccount;
544 | txtLoginToken.Text = currentAccount.GenerateSteamGuardCodeForTime(steamTime);
545 | groupAccount.Text = "Account: " + currentAccount.AccountName;
546 | }
547 | }
548 |
549 | ///
550 | /// Decrypts files and populates list UI with accounts
551 | ///
552 | private void loadAccountsList()
553 | {
554 | currentAccount = null;
555 |
556 | listAccounts.Items.Clear();
557 | listAccounts.SelectedIndex = -1;
558 |
559 | trayAccountList.Items.Clear();
560 | trayAccountList.SelectedIndex = -1;
561 |
562 | allAccounts = manifest.GetAllAccounts(passKey);
563 |
564 | if (allAccounts.Length > 0)
565 | {
566 | for (int i = 0; i < allAccounts.Length; i++)
567 | {
568 | SteamGuardAccount account = allAccounts[i];
569 | listAccounts.Items.Add(account.AccountName);
570 | trayAccountList.Items.Add(account.AccountName);
571 | }
572 |
573 | listAccounts.SelectedIndex = 0;
574 | trayAccountList.SelectedIndex = 0;
575 |
576 | listAccounts.Sorted = true;
577 | trayAccountList.Sorted = true;
578 | }
579 | menuDeactivateAuthenticator.Enabled = btnTradeConfirmations.Enabled = allAccounts.Length > 0;
580 | }
581 |
582 | private void listAccounts_KeyDown(object sender, KeyEventArgs e)
583 | {
584 | if (e.Control)
585 | {
586 | if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down)
587 | {
588 | int to = listAccounts.SelectedIndex - (e.KeyCode == Keys.Up ? 1 : -1);
589 | manifest.MoveEntry(listAccounts.SelectedIndex, to);
590 | loadAccountsList();
591 | }
592 | return;
593 | }
594 |
595 | if (!IsKeyAChar(e.KeyCode) && !IsKeyADigit(e.KeyCode))
596 | {
597 | return;
598 | }
599 |
600 | txtAccSearch.Focus();
601 | txtAccSearch.Text = e.KeyCode.ToString();
602 | txtAccSearch.SelectionStart = 1;
603 | }
604 |
605 | private static bool IsKeyAChar(Keys key)
606 | {
607 | return key >= Keys.A && key <= Keys.Z;
608 | }
609 |
610 | private static bool IsKeyADigit(Keys key)
611 | {
612 | return (key >= Keys.D0 && key <= Keys.D9) || (key >= Keys.NumPad0 && key <= Keys.NumPad9);
613 | }
614 |
615 | private bool IsFilter(string f)
616 | {
617 | if (txtAccSearch.Text.StartsWith("~"))
618 | {
619 | try
620 | {
621 | return Regex.IsMatch(f, txtAccSearch.Text);
622 | }
623 | catch (Exception)
624 | {
625 | return true;
626 | }
627 |
628 | }
629 | else
630 | {
631 | return f.Contains(txtAccSearch.Text);
632 | }
633 | }
634 |
635 | private string[] getAllNames()
636 | {
637 | string[] itemArray = new string[allAccounts.Length];
638 | for (int i = 0; i < itemArray.Length; i++)
639 | {
640 | itemArray[i] = allAccounts[i].AccountName;
641 | }
642 | return itemArray;
643 | }
644 |
645 | private void loadSettings()
646 | {
647 | timerTradesPopup.Enabled = manifest.PeriodicChecking;
648 | timerTradesPopup.Interval = manifest.PeriodicCheckingInterval * 1000;
649 | }
650 |
651 | // Logic for version checking
652 | private Version newVersion = null;
653 | private Version currentVersion = null;
654 | private WebClient updateClient = null;
655 | private string updateUrl = null;
656 | private bool startupUpdateCheck = true;
657 |
658 | private void checkForUpdates()
659 | {
660 | if (updateClient != null) return;
661 | updateClient = new WebClient();
662 | updateClient.DownloadStringCompleted += UpdateClient_DownloadStringCompleted;
663 | updateClient.Headers.Add("Content-Type", "application/json");
664 | updateClient.Headers.Add("User-Agent", "Steam Desktop Authenticator");
665 | updateClient.DownloadStringAsync(new Uri("https://api.github.com/repos/Jessecar96/SteamDesktopAuthenticator/releases/latest"));
666 | }
667 |
668 | private void compareVersions()
669 | {
670 | if (newVersion > currentVersion)
671 | {
672 | labelUpdate.Text = "Download new version"; // Show the user a new version is available if they press no
673 | DialogResult updateDialog = MessageBox.Show(String.Format("A new version is available! Would you like to download it now?\nYou will update from version {0} to {1}", Application.ProductVersion, newVersion.ToString()), "New Version", MessageBoxButtons.YesNo);
674 | if (updateDialog == DialogResult.Yes)
675 | {
676 | Process.Start(updateUrl);
677 | }
678 | }
679 | else
680 | {
681 | if (!startupUpdateCheck)
682 | {
683 | MessageBox.Show(String.Format("You are using the latest version: {0}", Application.ProductVersion));
684 | }
685 | }
686 |
687 | newVersion = null; // Check the api again next time they check for updates
688 | updateClient = null; // Set to null to indicate it's done checking
689 | startupUpdateCheck = false; // Set when it's done checking on startup
690 | }
691 |
692 | private void UpdateClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
693 | {
694 | try
695 | {
696 | dynamic resultObject = JsonConvert.DeserializeObject(e.Result);
697 | newVersion = new Version(resultObject.tag_name.Value);
698 | currentVersion = new Version(Application.ProductVersion);
699 | updateUrl = resultObject.assets.First.browser_download_url.Value;
700 | compareVersions();
701 | }
702 | catch (Exception)
703 | {
704 | MessageBox.Show("Failed to check for updates.");
705 | }
706 | }
707 |
708 | private void MainForm_KeyDown(object sender, KeyEventArgs e)
709 | {
710 | if (e.KeyCode == Keys.C && e.Modifiers == Keys.Control)
711 | {
712 | CopyLoginToken();
713 | }
714 | }
715 |
716 | private void panelButtons_SizeChanged(object sender, EventArgs e)
717 | {
718 | int totButtons = panelButtons.Controls.OfType().Count();
719 |
720 | Point curPos = new Point(0, 0);
721 | foreach (Button but in panelButtons.Controls.OfType())
722 | {
723 | but.Width = panelButtons.Width / totButtons;
724 | but.Location = curPos;
725 | curPos = new Point(curPos.X + but.Width, 0);
726 | }
727 | }
728 | }
729 | }
730 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/Manifest.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using SteamAuth;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 |
11 | namespace Steam_Desktop_Authenticator
12 | {
13 | public class Manifest
14 | {
15 | [JsonProperty("encrypted")]
16 | public bool Encrypted { get; set; }
17 |
18 | [JsonProperty("first_run")]
19 | public bool FirstRun { get; set; } = true;
20 |
21 | [JsonProperty("entries")]
22 | public List Entries { get; set; }
23 |
24 | [JsonProperty("periodic_checking")]
25 | public bool PeriodicChecking { get; set; } = false;
26 |
27 | [JsonProperty("periodic_checking_interval")]
28 | public int PeriodicCheckingInterval { get; set; } = 5;
29 |
30 | [JsonProperty("periodic_checking_checkall")]
31 | public bool CheckAllAccounts { get; set; } = false;
32 |
33 | [JsonProperty("auto_confirm_market_transactions")]
34 | public bool AutoConfirmMarketTransactions { get; set; } = false;
35 |
36 | [JsonProperty("auto_confirm_trades")]
37 | public bool AutoConfirmTrades { get; set; } = false;
38 |
39 | private static Manifest _manifest { get; set; }
40 |
41 | public static string GetExecutableDir()
42 | {
43 | return Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
44 | }
45 |
46 | public static Manifest GetManifest(bool forceLoad = false)
47 | {
48 | // Check if already staticly loaded
49 | if (_manifest != null && !forceLoad)
50 | {
51 | return _manifest;
52 | }
53 |
54 | // Find config dir and manifest file
55 | string maDir = Manifest.GetExecutableDir() + "/maFiles/";
56 | string manifestFile = maDir + "manifest.json";
57 |
58 | // If there's no config dir, create it
59 | if (!Directory.Exists(maDir))
60 | {
61 | _manifest = GenerateNewManifest(false);
62 | return _manifest;
63 | }
64 |
65 | // If there's no manifest, throw exception
66 | if (!File.Exists(manifestFile))
67 | {
68 | throw new ManifestParseException();
69 | }
70 |
71 | try
72 | {
73 | string manifestContents = File.ReadAllText(manifestFile);
74 | _manifest = JsonConvert.DeserializeObject(manifestContents);
75 |
76 | if (_manifest.Encrypted && _manifest.Entries.Count == 0)
77 | {
78 | _manifest.Encrypted = false;
79 | _manifest.Save();
80 | }
81 |
82 | _manifest.RecomputeExistingEntries();
83 |
84 | return _manifest;
85 | }
86 | catch (Exception)
87 | {
88 | throw new ManifestParseException();
89 | }
90 | }
91 |
92 | public static Manifest GenerateNewManifest(bool scanDir = false)
93 | {
94 | // No directory means no manifest file anyways.
95 | Manifest newManifest = new Manifest();
96 | newManifest.Encrypted = false;
97 | newManifest.PeriodicCheckingInterval = 5;
98 | newManifest.PeriodicChecking = false;
99 | newManifest.AutoConfirmMarketTransactions = false;
100 | newManifest.AutoConfirmTrades = false;
101 | newManifest.Entries = new List();
102 | newManifest.FirstRun = true;
103 |
104 | // Take a pre-manifest version and generate a manifest for it.
105 | if (scanDir)
106 | {
107 | string maDir = Manifest.GetExecutableDir() + "/maFiles/";
108 | if (Directory.Exists(maDir))
109 | {
110 | DirectoryInfo dir = new DirectoryInfo(maDir);
111 | var files = dir.GetFiles();
112 |
113 | foreach (var file in files)
114 | {
115 | if (file.Extension != ".maFile") continue;
116 |
117 | string contents = File.ReadAllText(file.FullName);
118 | try
119 | {
120 | SteamGuardAccount account = JsonConvert.DeserializeObject(contents);
121 | ManifestEntry newEntry = new ManifestEntry()
122 | {
123 | Filename = file.Name,
124 | SteamID = account.Session.SteamID
125 | };
126 | newManifest.Entries.Add(newEntry);
127 | }
128 | catch (Exception)
129 | {
130 | throw new MaFileEncryptedException();
131 | }
132 | }
133 |
134 | if (newManifest.Entries.Count > 0)
135 | {
136 | newManifest.Save();
137 | newManifest.PromptSetupPassKey("This version of SDA has encryption. Please enter a passkey below, or hit cancel to remain unencrypted");
138 | }
139 | }
140 | }
141 |
142 | if (newManifest.Save())
143 | {
144 | return newManifest;
145 | }
146 |
147 | return null;
148 | }
149 |
150 | public class IncorrectPassKeyException : Exception { }
151 | public class ManifestNotEncryptedException : Exception { }
152 |
153 | public string PromptForPassKey()
154 | {
155 | if (!this.Encrypted)
156 | {
157 | throw new ManifestNotEncryptedException();
158 | }
159 |
160 | bool passKeyValid = false;
161 | string passKey = null;
162 | while (!passKeyValid)
163 | {
164 | InputForm passKeyForm = new InputForm("Please enter your encryption passkey.", true);
165 | passKeyForm.ShowDialog();
166 | if (!passKeyForm.Canceled)
167 | {
168 | passKey = passKeyForm.txtBox.Text;
169 | passKeyValid = this.VerifyPasskey(passKey);
170 | if (!passKeyValid)
171 | {
172 | MessageBox.Show("That passkey is invalid.");
173 | }
174 | }
175 | else
176 | {
177 | return null;
178 | }
179 | }
180 | return passKey;
181 | }
182 |
183 | public string PromptSetupPassKey(string initialPrompt = "Enter passkey, or hit cancel to remain unencrypted.")
184 | {
185 | InputForm newPassKeyForm = new InputForm(initialPrompt);
186 | newPassKeyForm.ShowDialog();
187 | if (newPassKeyForm.Canceled || newPassKeyForm.txtBox.Text.Length == 0)
188 | {
189 | MessageBox.Show("WARNING: You chose to not encrypt your files. Doing so imposes a security risk for yourself. If an attacker were to gain access to your computer, they could completely lock you out of your account and steal all your items.");
190 | return null;
191 | }
192 |
193 | InputForm newPassKeyForm2 = new InputForm("Confirm new passkey.");
194 | newPassKeyForm2.ShowDialog();
195 | if (newPassKeyForm2.Canceled)
196 | {
197 | MessageBox.Show("WARNING: You chose to not encrypt your files. Doing so imposes a security risk for yourself. If an attacker were to gain access to your computer, they could completely lock you out of your account and steal all your items.");
198 | return null;
199 | }
200 |
201 | string newPassKey = newPassKeyForm.txtBox.Text;
202 | string confirmPassKey = newPassKeyForm2.txtBox.Text;
203 |
204 | if (newPassKey != confirmPassKey)
205 | {
206 | MessageBox.Show("Passkeys do not match.");
207 | return null;
208 | }
209 |
210 | if (!this.ChangeEncryptionKey(null, newPassKey))
211 | {
212 | MessageBox.Show("Unable to set passkey.");
213 | return null;
214 | }
215 | else
216 | {
217 | MessageBox.Show("Passkey successfully set.");
218 | }
219 |
220 | return newPassKey;
221 | }
222 |
223 | public SteamAuth.SteamGuardAccount[] GetAllAccounts(string passKey = null, int limit = -1)
224 | {
225 | if (passKey == null && this.Encrypted) return new SteamGuardAccount[0];
226 | string maDir = Manifest.GetExecutableDir() + "/maFiles/";
227 |
228 | List accounts = new List();
229 | foreach (var entry in this.Entries)
230 | {
231 | string fileText = File.ReadAllText(maDir + entry.Filename);
232 | if (this.Encrypted)
233 | {
234 | string decryptedText = FileEncryptor.DecryptData(passKey, entry.Salt, entry.IV, fileText);
235 | if (decryptedText == null) return new SteamGuardAccount[0];
236 | fileText = decryptedText;
237 | }
238 |
239 | var account = JsonConvert.DeserializeObject(fileText);
240 | if (account == null) continue;
241 | accounts.Add(account);
242 |
243 | if (limit != -1 && limit >= accounts.Count)
244 | break;
245 | }
246 |
247 | return accounts.ToArray();
248 | }
249 |
250 | public bool ChangeEncryptionKey(string oldKey, string newKey)
251 | {
252 | if (this.Encrypted)
253 | {
254 | if (!this.VerifyPasskey(oldKey))
255 | {
256 | return false;
257 | }
258 | }
259 | bool toEncrypt = newKey != null;
260 |
261 | string maDir = Manifest.GetExecutableDir() + "/maFiles/";
262 | for (int i = 0; i < this.Entries.Count; i++)
263 | {
264 | ManifestEntry entry = this.Entries[i];
265 | string filename = maDir + entry.Filename;
266 | if (!File.Exists(filename)) continue;
267 |
268 | string fileContents = File.ReadAllText(filename);
269 | if (this.Encrypted)
270 | {
271 | fileContents = FileEncryptor.DecryptData(oldKey, entry.Salt, entry.IV, fileContents);
272 | }
273 |
274 | string newSalt = null;
275 | string newIV = null;
276 | string toWriteFileContents = fileContents;
277 |
278 | if (toEncrypt)
279 | {
280 | newSalt = FileEncryptor.GetRandomSalt();
281 | newIV = FileEncryptor.GetInitializationVector();
282 | toWriteFileContents = FileEncryptor.EncryptData(newKey, newSalt, newIV, fileContents);
283 | }
284 |
285 | File.WriteAllText(filename, toWriteFileContents);
286 | entry.IV = newIV;
287 | entry.Salt = newSalt;
288 | }
289 |
290 | this.Encrypted = toEncrypt;
291 |
292 | this.Save();
293 | return true;
294 | }
295 |
296 | public bool VerifyPasskey(string passkey)
297 | {
298 | if (!this.Encrypted || this.Entries.Count == 0) return true;
299 |
300 | var accounts = this.GetAllAccounts(passkey, 1);
301 | return accounts != null && accounts.Length == 1;
302 | }
303 |
304 | public bool RemoveAccount(SteamGuardAccount account, bool deleteMaFile = true)
305 | {
306 | ManifestEntry entry = (from e in this.Entries where e.SteamID == account.Session.SteamID select e).FirstOrDefault();
307 | if (entry == null) return true; // If something never existed, did you do what they asked?
308 |
309 | string maDir = Manifest.GetExecutableDir() + "/maFiles/";
310 | string filename = maDir + entry.Filename;
311 | this.Entries.Remove(entry);
312 |
313 | if (this.Entries.Count == 0)
314 | {
315 | this.Encrypted = false;
316 | }
317 |
318 | if (this.Save() && deleteMaFile)
319 | {
320 | try
321 | {
322 | File.Delete(filename);
323 | return true;
324 | }
325 | catch (Exception)
326 | {
327 | return false;
328 | }
329 | }
330 |
331 | return false;
332 | }
333 |
334 | public bool SaveAccount(SteamGuardAccount account, bool encrypt, string passKey = null)
335 | {
336 | if (encrypt && String.IsNullOrEmpty(passKey)) return false;
337 | if (!encrypt && this.Encrypted) return false;
338 |
339 | string salt = null;
340 | string iV = null;
341 | string jsonAccount = JsonConvert.SerializeObject(account);
342 |
343 | if (encrypt)
344 | {
345 | salt = FileEncryptor.GetRandomSalt();
346 | iV = FileEncryptor.GetInitializationVector();
347 | string encrypted = FileEncryptor.EncryptData(passKey, salt, iV, jsonAccount);
348 | if (encrypted == null) return false;
349 | jsonAccount = encrypted;
350 | }
351 |
352 | string maDir = Manifest.GetExecutableDir() + "/maFiles/";
353 | string filename = account.Session.SteamID.ToString() + ".maFile";
354 |
355 | ManifestEntry newEntry = new ManifestEntry()
356 | {
357 | SteamID = account.Session.SteamID,
358 | IV = iV,
359 | Salt = salt,
360 | Filename = filename
361 | };
362 |
363 | bool foundExistingEntry = false;
364 | for (int i = 0; i < this.Entries.Count; i++)
365 | {
366 | if (this.Entries[i].SteamID == account.Session.SteamID)
367 | {
368 | this.Entries[i] = newEntry;
369 | foundExistingEntry = true;
370 | break;
371 | }
372 | }
373 |
374 | if (!foundExistingEntry)
375 | {
376 | this.Entries.Add(newEntry);
377 | }
378 |
379 | bool wasEncrypted = this.Encrypted;
380 | this.Encrypted = encrypt || this.Encrypted;
381 |
382 | if (!this.Save())
383 | {
384 | this.Encrypted = wasEncrypted;
385 | return false;
386 | }
387 |
388 | try
389 | {
390 | File.WriteAllText(maDir + filename, jsonAccount);
391 | return true;
392 | }
393 | catch (Exception)
394 | {
395 | return false;
396 | }
397 | }
398 |
399 | public bool Save()
400 | {
401 | string maDir = Manifest.GetExecutableDir() + "/maFiles/";
402 | string filename = maDir + "manifest.json";
403 | if (!Directory.Exists(maDir))
404 | {
405 | try
406 | {
407 | Directory.CreateDirectory(maDir);
408 | }
409 | catch (Exception)
410 | {
411 | return false;
412 | }
413 | }
414 |
415 | try
416 | {
417 | string contents = JsonConvert.SerializeObject(this);
418 | File.WriteAllText(filename, contents);
419 | return true;
420 | }
421 | catch (Exception)
422 | {
423 | return false;
424 | }
425 | }
426 |
427 | private void RecomputeExistingEntries()
428 | {
429 | List newEntries = new List();
430 | string maDir = Manifest.GetExecutableDir() + "/maFiles/";
431 |
432 | foreach (var entry in this.Entries)
433 | {
434 | string filename = maDir + entry.Filename;
435 | if (File.Exists(filename))
436 | {
437 | newEntries.Add(entry);
438 | }
439 | }
440 |
441 | this.Entries = newEntries;
442 |
443 | if (this.Entries.Count == 0)
444 | {
445 | this.Encrypted = false;
446 | }
447 | }
448 |
449 | public void MoveEntry(int from, int to)
450 | {
451 | if (from < 0 || to < 0 || from > Entries.Count || to > Entries.Count - 1) return;
452 | ManifestEntry sel = Entries[from];
453 | Entries.RemoveAt(from);
454 | Entries.Insert(to, sel);
455 | Save();
456 | }
457 |
458 | public class ManifestEntry
459 | {
460 | [JsonProperty("encryption_iv")]
461 | public string IV { get; set; }
462 |
463 | [JsonProperty("encryption_salt")]
464 | public string Salt { get; set; }
465 |
466 | [JsonProperty("filename")]
467 | public string Filename { get; set; }
468 |
469 | [JsonProperty("steamid")]
470 | public ulong SteamID { get; set; }
471 | }
472 | }
473 | }
474 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/ManifestParseException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Steam_Desktop_Authenticator
8 | {
9 | class ManifestParseException : Exception
10 | {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/PhoneInputForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Steam_Desktop_Authenticator
2 | {
3 | partial class PhoneInputForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PhoneInputForm));
32 | this.txtCountryCode = new System.Windows.Forms.MaskedTextBox();
33 | this.label1 = new System.Windows.Forms.Label();
34 | this.label2 = new System.Windows.Forms.Label();
35 | this.label3 = new System.Windows.Forms.Label();
36 | this.txtPhoneNumber = new System.Windows.Forms.MaskedTextBox();
37 | this.btnSubmit = new System.Windows.Forms.Button();
38 | this.btnCancel = new System.Windows.Forms.Button();
39 | this.SuspendLayout();
40 | //
41 | // txtCountryCode
42 | //
43 | this.txtCountryCode.AsciiOnly = true;
44 | this.txtCountryCode.Font = new System.Drawing.Font("Segoe UI", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
45 | this.txtCountryCode.Location = new System.Drawing.Point(11, 98);
46 | this.txtCountryCode.Margin = new System.Windows.Forms.Padding(2);
47 | this.txtCountryCode.Mask = "AA";
48 | this.txtCountryCode.Name = "txtCountryCode";
49 | this.txtCountryCode.Size = new System.Drawing.Size(68, 33);
50 | this.txtCountryCode.TabIndex = 0;
51 | this.txtCountryCode.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.txtCountryCode_KeyPress);
52 | this.txtCountryCode.Leave += new System.EventHandler(this.txtCountryCode_Leave);
53 | //
54 | // label1
55 | //
56 | this.label1.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
57 | this.label1.Location = new System.Drawing.Point(8, 12);
58 | this.label1.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
59 | this.label1.Name = "label1";
60 | this.label1.Size = new System.Drawing.Size(556, 66);
61 | this.label1.TabIndex = 1;
62 | this.label1.Text = "Your Steam account requires a phone number to add a mobile authenticator. \r\nThis " +
63 | "phone number must be able to receieve SMS. \r\nVoIP and virtual phone numbers are " +
64 | "not supported.";
65 | //
66 | // label2
67 | //
68 | this.label2.AutoSize = true;
69 | this.label2.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
70 | this.label2.Location = new System.Drawing.Point(8, 77);
71 | this.label2.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
72 | this.label2.Name = "label2";
73 | this.label2.Size = new System.Drawing.Size(276, 17);
74 | this.label2.TabIndex = 2;
75 | this.label2.Text = "Two letter country code of the phone number:";
76 | //
77 | // label3
78 | //
79 | this.label3.AutoSize = true;
80 | this.label3.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
81 | this.label3.Location = new System.Drawing.Point(8, 137);
82 | this.label3.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
83 | this.label3.Name = "label3";
84 | this.label3.Size = new System.Drawing.Size(201, 17);
85 | this.label3.TabIndex = 3;
86 | this.label3.Text = "Phone Number: (+1 0000000000)";
87 | //
88 | // txtPhoneNumber
89 | //
90 | this.txtPhoneNumber.Font = new System.Drawing.Font("Segoe UI", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
91 | this.txtPhoneNumber.Location = new System.Drawing.Point(11, 158);
92 | this.txtPhoneNumber.Margin = new System.Windows.Forms.Padding(2);
93 | this.txtPhoneNumber.Name = "txtPhoneNumber";
94 | this.txtPhoneNumber.Size = new System.Drawing.Size(198, 33);
95 | this.txtPhoneNumber.TabIndex = 4;
96 | this.txtPhoneNumber.Text = "+1 ";
97 | this.txtPhoneNumber.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.txtPhoneNumber_KeyPress);
98 | //
99 | // btnSubmit
100 | //
101 | this.btnSubmit.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
102 | this.btnSubmit.Location = new System.Drawing.Point(11, 197);
103 | this.btnSubmit.Margin = new System.Windows.Forms.Padding(2);
104 | this.btnSubmit.Name = "btnSubmit";
105 | this.btnSubmit.Size = new System.Drawing.Size(85, 31);
106 | this.btnSubmit.TabIndex = 5;
107 | this.btnSubmit.Text = "Submit";
108 | this.btnSubmit.UseVisualStyleBackColor = true;
109 | this.btnSubmit.Click += new System.EventHandler(this.btnSubmit_Click);
110 | //
111 | // btnCancel
112 | //
113 | this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
114 | this.btnCancel.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
115 | this.btnCancel.Location = new System.Drawing.Point(100, 197);
116 | this.btnCancel.Margin = new System.Windows.Forms.Padding(2);
117 | this.btnCancel.Name = "btnCancel";
118 | this.btnCancel.Size = new System.Drawing.Size(85, 31);
119 | this.btnCancel.TabIndex = 6;
120 | this.btnCancel.Text = "Cancel";
121 | this.btnCancel.UseVisualStyleBackColor = true;
122 | this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
123 | //
124 | // PhoneInputForm
125 | //
126 | this.AcceptButton = this.btnSubmit;
127 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
128 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
129 | this.CancelButton = this.btnCancel;
130 | this.ClientSize = new System.Drawing.Size(473, 239);
131 | this.Controls.Add(this.btnCancel);
132 | this.Controls.Add(this.btnSubmit);
133 | this.Controls.Add(this.txtPhoneNumber);
134 | this.Controls.Add(this.label3);
135 | this.Controls.Add(this.label2);
136 | this.Controls.Add(this.label1);
137 | this.Controls.Add(this.txtCountryCode);
138 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
139 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
140 | this.Margin = new System.Windows.Forms.Padding(2);
141 | this.MaximizeBox = false;
142 | this.Name = "PhoneInputForm";
143 | this.ShowInTaskbar = false;
144 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
145 | this.Text = "PhoneInputForm";
146 | this.ResumeLayout(false);
147 | this.PerformLayout();
148 |
149 | }
150 |
151 | #endregion
152 |
153 | private System.Windows.Forms.MaskedTextBox txtCountryCode;
154 | private System.Windows.Forms.Label label1;
155 | private System.Windows.Forms.Label label2;
156 | private System.Windows.Forms.Label label3;
157 | private System.Windows.Forms.MaskedTextBox txtPhoneNumber;
158 | private System.Windows.Forms.Button btnSubmit;
159 | private System.Windows.Forms.Button btnCancel;
160 | }
161 | }
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/PhoneInputForm.cs:
--------------------------------------------------------------------------------
1 | using SteamAuth;
2 | using System;
3 | using System.Text.RegularExpressions;
4 | using System.Windows.Forms;
5 |
6 | namespace Steam_Desktop_Authenticator
7 | {
8 | public partial class PhoneInputForm : Form
9 | {
10 | private SteamGuardAccount Account;
11 | public string PhoneNumber;
12 | public string CountryCode;
13 | public bool Canceled;
14 |
15 | public PhoneInputForm(SteamGuardAccount account)
16 | {
17 | this.Account = account;
18 | InitializeComponent();
19 | }
20 |
21 | private void btnSubmit_Click(object sender, EventArgs e)
22 | {
23 | this.PhoneNumber = txtPhoneNumber.Text;
24 | this.CountryCode = txtCountryCode.Text;
25 |
26 | if (this.PhoneNumber[0] != '+')
27 | {
28 | MessageBox.Show("Phone number must start with + and country code.", "Phone Number", MessageBoxButtons.OK, MessageBoxIcon.Error);
29 | return;
30 | }
31 |
32 | this.Close();
33 | }
34 |
35 | private void txtPhoneNumber_KeyPress(object sender, KeyPressEventArgs e)
36 | {
37 | // Allow pasting
38 | if (Char.IsControl(e.KeyChar))
39 | return;
40 |
41 | // Only allow numbers, spaces, and +
42 | var regex = new Regex(@"[^0-9\s\+]");
43 | if (regex.IsMatch(e.KeyChar.ToString()))
44 | {
45 | e.Handled = true;
46 | }
47 | }
48 |
49 | private void txtCountryCode_KeyPress(object sender, KeyPressEventArgs e)
50 | {
51 | // Allow pasting
52 | if (Char.IsControl(e.KeyChar))
53 | return;
54 |
55 | // Only allow letters
56 | var regex = new Regex(@"[^a-zA-Z]");
57 | if (regex.IsMatch(e.KeyChar.ToString()))
58 | {
59 | e.Handled = true;
60 | }
61 | }
62 |
63 | private void txtCountryCode_Leave(object sender, EventArgs e)
64 | {
65 | // Always uppercase
66 | txtCountryCode.Text = txtCountryCode.Text.ToUpper();
67 | }
68 |
69 | private void btnCancel_Click(object sender, EventArgs e)
70 | {
71 | this.Canceled = true;
72 | this.Close();
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 | using System.Diagnostics;
4 | using CommandLine;
5 |
6 | namespace Steam_Desktop_Authenticator
7 | {
8 | static class Program
9 | {
10 | public static Process PriorProcess()
11 | // Returns a System.Diagnostics.Process pointing to
12 | // a pre-existing process with the same name as the
13 | // current one, if any; or null if the current process
14 | // is unique.
15 | {
16 | try
17 | {
18 | Process curr = Process.GetCurrentProcess();
19 | Process[] procs = Process.GetProcessesByName(curr.ProcessName);
20 | foreach (Process p in procs)
21 | {
22 | if ((p.Id != curr.Id) &&
23 | (p.MainModule.FileName == curr.MainModule.FileName))
24 | return p;
25 | }
26 | return null;
27 | }
28 | catch (Exception)
29 | {
30 | return null;
31 | }
32 | }
33 |
34 | ///
35 | /// The main entry point for the application.
36 | ///
37 | [STAThread]
38 | static void Main(string[] args)
39 | {
40 | // run the program only once
41 | if (PriorProcess() != null)
42 | {
43 | MessageBox.Show("Another instance of the app is already running.");
44 | return;
45 | }
46 |
47 | // Parse command line arguments
48 | var options = new CommandLineOptions();
49 | Parser.Default.ParseArguments(args, options);
50 |
51 | Application.EnableVisualStyles();
52 | Application.SetCompatibleTextRenderingDefault(false);
53 |
54 | Manifest man;
55 |
56 | try
57 | {
58 | man = Manifest.GetManifest();
59 | }
60 | catch (ManifestParseException)
61 | {
62 | // Manifest file was corrupted, generate a new one.
63 | try
64 | {
65 | MessageBox.Show("Your settings were unexpectedly corrupted and were reset to defaults.", "Steam Desktop Authenticator", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
66 | man = Manifest.GenerateNewManifest(true);
67 | }
68 | catch (MaFileEncryptedException)
69 | {
70 | // An maFile was encrypted, we're fucked.
71 | MessageBox.Show("Sorry, but SDA was unable to recover your accounts since you used encryption.\nYou'll need to recover your Steam accounts by removing the authenticator.\nClick OK to view instructions.", "Steam Desktop Authenticator", MessageBoxButtons.OK, MessageBoxIcon.Error);
72 | System.Diagnostics.Process.Start(@"https://github.com/Jessecar96/SteamDesktopAuthenticator/wiki/Help!-I'm-locked-out-of-my-account");
73 | return;
74 | }
75 | }
76 |
77 | if (man.FirstRun)
78 | {
79 | if (man.Entries.Count > 0)
80 | {
81 | // Already has accounts, just run
82 | MainForm mf = new MainForm();
83 | mf.SetEncryptionKey(options.EncryptionKey);
84 | mf.StartSilent(options.Silent);
85 | Application.Run(mf);
86 | }
87 | else
88 | {
89 | // No accounts, run welcome form
90 | Application.Run(new WelcomeForm());
91 | }
92 | }
93 | else
94 | {
95 | MainForm mf = new MainForm();
96 | mf.SetEncryptionKey(options.EncryptionKey);
97 | mf.StartSilent(options.Silent);
98 | Application.Run(mf);
99 | }
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Steam Desktop Authenticator")]
9 | [assembly: AssemblyDescription("Desktop implementation of Steam's mobile authenticator app")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Steam Desktop Authenticator")]
13 | [assembly: AssemblyCopyright("Copyright 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(true)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("0f37c513-9af4-42c8-9ce9-f9b3bfa55e4e")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.14")]
36 | [assembly: AssemblyFileVersion("1.0.14")]
37 |
38 | [assembly: AssemblyMetadata("SquirrelAwareVersion", "1")]
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/SettingsForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Steam_Desktop_Authenticator
2 | {
3 | partial class SettingsForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SettingsForm));
32 | this.chkPeriodicChecking = new System.Windows.Forms.CheckBox();
33 | this.btnSave = new System.Windows.Forms.Button();
34 | this.numPeriodicInterval = new System.Windows.Forms.NumericUpDown();
35 | this.label1 = new System.Windows.Forms.Label();
36 | this.chkCheckAll = new System.Windows.Forms.CheckBox();
37 | this.chkConfirmMarket = new System.Windows.Forms.CheckBox();
38 | this.chkConfirmTrades = new System.Windows.Forms.CheckBox();
39 | ((System.ComponentModel.ISupportInitialize)(this.numPeriodicInterval)).BeginInit();
40 | this.SuspendLayout();
41 | //
42 | // chkPeriodicChecking
43 | //
44 | this.chkPeriodicChecking.AutoSize = true;
45 | this.chkPeriodicChecking.Location = new System.Drawing.Point(12, 12);
46 | this.chkPeriodicChecking.Name = "chkPeriodicChecking";
47 | this.chkPeriodicChecking.Size = new System.Drawing.Size(233, 30);
48 | this.chkPeriodicChecking.TabIndex = 0;
49 | this.chkPeriodicChecking.Text = "Periodically check for new confirmations\r\nand show a popup when they arrive";
50 | this.chkPeriodicChecking.UseVisualStyleBackColor = true;
51 | this.chkPeriodicChecking.CheckedChanged += new System.EventHandler(this.chkPeriodicChecking_CheckedChanged);
52 | //
53 | // btnSave
54 | //
55 | this.btnSave.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
56 | | System.Windows.Forms.AnchorStyles.Right)));
57 | this.btnSave.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
58 | this.btnSave.Location = new System.Drawing.Point(12, 152);
59 | this.btnSave.Name = "btnSave";
60 | this.btnSave.Size = new System.Drawing.Size(224, 38);
61 | this.btnSave.TabIndex = 1;
62 | this.btnSave.Text = "Save";
63 | this.btnSave.UseVisualStyleBackColor = true;
64 | this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
65 | //
66 | // numPeriodicInterval
67 | //
68 | this.numPeriodicInterval.Location = new System.Drawing.Point(12, 51);
69 | this.numPeriodicInterval.Minimum = new decimal(new int[] {
70 | 5,
71 | 0,
72 | 0,
73 | 0});
74 | this.numPeriodicInterval.Name = "numPeriodicInterval";
75 | this.numPeriodicInterval.Size = new System.Drawing.Size(41, 22);
76 | this.numPeriodicInterval.TabIndex = 2;
77 | this.numPeriodicInterval.Value = new decimal(new int[] {
78 | 5,
79 | 0,
80 | 0,
81 | 0});
82 | //
83 | // label1
84 | //
85 | this.label1.AutoSize = true;
86 | this.label1.Location = new System.Drawing.Point(59, 49);
87 | this.label1.Name = "label1";
88 | this.label1.Size = new System.Drawing.Size(150, 26);
89 | this.label1.TabIndex = 3;
90 | this.label1.Text = "Seconds between checking \r\nfor confirmations";
91 | //
92 | // chkCheckAll
93 | //
94 | this.chkCheckAll.AutoSize = true;
95 | this.chkCheckAll.Location = new System.Drawing.Point(12, 81);
96 | this.chkCheckAll.Name = "chkCheckAll";
97 | this.chkCheckAll.Size = new System.Drawing.Size(213, 17);
98 | this.chkCheckAll.TabIndex = 4;
99 | this.chkCheckAll.Text = "Check all accounts for confirmations";
100 | this.chkCheckAll.UseVisualStyleBackColor = true;
101 | //
102 | // chkConfirmMarket
103 | //
104 | this.chkConfirmMarket.AutoSize = true;
105 | this.chkConfirmMarket.Location = new System.Drawing.Point(12, 104);
106 | this.chkConfirmMarket.Name = "chkConfirmMarket";
107 | this.chkConfirmMarket.Size = new System.Drawing.Size(198, 17);
108 | this.chkConfirmMarket.TabIndex = 5;
109 | this.chkConfirmMarket.Text = "Auto-confirm market transactions";
110 | this.chkConfirmMarket.UseVisualStyleBackColor = true;
111 | this.chkConfirmMarket.CheckedChanged += new System.EventHandler(this.chkConfirmMarket_CheckedChanged);
112 | //
113 | // chkConfirmTrades
114 | //
115 | this.chkConfirmTrades.AutoSize = true;
116 | this.chkConfirmTrades.Location = new System.Drawing.Point(12, 127);
117 | this.chkConfirmTrades.Name = "chkConfirmTrades";
118 | this.chkConfirmTrades.Size = new System.Drawing.Size(129, 17);
119 | this.chkConfirmTrades.TabIndex = 6;
120 | this.chkConfirmTrades.Text = "Auto-confirm trades";
121 | this.chkConfirmTrades.UseVisualStyleBackColor = true;
122 | this.chkConfirmTrades.CheckedChanged += new System.EventHandler(this.chkConfirmTrades_CheckedChanged);
123 | //
124 | // SettingsForm
125 | //
126 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
127 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
128 | this.ClientSize = new System.Drawing.Size(244, 202);
129 | this.Controls.Add(this.chkConfirmTrades);
130 | this.Controls.Add(this.chkConfirmMarket);
131 | this.Controls.Add(this.chkCheckAll);
132 | this.Controls.Add(this.label1);
133 | this.Controls.Add(this.numPeriodicInterval);
134 | this.Controls.Add(this.btnSave);
135 | this.Controls.Add(this.chkPeriodicChecking);
136 | this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
137 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
138 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
139 | this.MaximizeBox = false;
140 | this.Name = "SettingsForm";
141 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
142 | this.Text = "Settings";
143 | ((System.ComponentModel.ISupportInitialize)(this.numPeriodicInterval)).EndInit();
144 | this.ResumeLayout(false);
145 | this.PerformLayout();
146 |
147 | }
148 |
149 | #endregion
150 |
151 | private System.Windows.Forms.CheckBox chkPeriodicChecking;
152 | private System.Windows.Forms.Button btnSave;
153 | private System.Windows.Forms.NumericUpDown numPeriodicInterval;
154 | private System.Windows.Forms.Label label1;
155 | private System.Windows.Forms.CheckBox chkCheckAll;
156 | private System.Windows.Forms.CheckBox chkConfirmMarket;
157 | private System.Windows.Forms.CheckBox chkConfirmTrades;
158 | }
159 | }
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/SettingsForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace Steam_Desktop_Authenticator
5 | {
6 | public partial class SettingsForm : Form
7 | {
8 | Manifest manifest;
9 | bool fullyLoaded = false;
10 |
11 | public SettingsForm()
12 | {
13 | InitializeComponent();
14 |
15 | // Get latest manifest
16 | manifest = Manifest.GetManifest(true);
17 |
18 | chkPeriodicChecking.Checked = manifest.PeriodicChecking;
19 | numPeriodicInterval.Value = manifest.PeriodicCheckingInterval;
20 | chkCheckAll.Checked = manifest.CheckAllAccounts;
21 | chkConfirmMarket.Checked = manifest.AutoConfirmMarketTransactions;
22 | chkConfirmTrades.Checked = manifest.AutoConfirmTrades;
23 |
24 | SetControlsEnabledState(chkPeriodicChecking.Checked);
25 |
26 | fullyLoaded = true;
27 | }
28 |
29 | private void SetControlsEnabledState(bool enabled)
30 | {
31 | numPeriodicInterval.Enabled = chkCheckAll.Enabled = chkConfirmMarket.Enabled = chkConfirmTrades.Enabled = enabled;
32 | }
33 |
34 | private void ShowWarning(CheckBox affectedBox)
35 | {
36 | if (!fullyLoaded) return;
37 |
38 | var result = MessageBox.Show("Warning: enabling this will severely reduce the security of your items! Use of this option is at your own risk. Would you like to continue?", "Warning!", MessageBoxButtons.YesNo);
39 | if (result == DialogResult.No)
40 | {
41 | affectedBox.Checked = false;
42 | }
43 | }
44 |
45 | private void btnSave_Click(object sender, EventArgs e)
46 | {
47 | manifest.PeriodicChecking = chkPeriodicChecking.Checked;
48 | manifest.PeriodicCheckingInterval = (int)numPeriodicInterval.Value;
49 | manifest.CheckAllAccounts = chkCheckAll.Checked;
50 | manifest.AutoConfirmMarketTransactions = chkConfirmMarket.Checked;
51 | manifest.AutoConfirmTrades = chkConfirmTrades.Checked;
52 | manifest.Save();
53 | this.Close();
54 | }
55 |
56 | private void chkPeriodicChecking_CheckedChanged(object sender, EventArgs e)
57 | {
58 | SetControlsEnabledState(chkPeriodicChecking.Checked);
59 | }
60 |
61 | private void chkConfirmMarket_CheckedChanged(object sender, EventArgs e)
62 | {
63 | if (chkConfirmMarket.Checked)
64 | ShowWarning(chkConfirmMarket);
65 | }
66 |
67 | private void chkConfirmTrades_CheckedChanged(object sender, EventArgs e)
68 | {
69 | if (chkConfirmTrades.Checked)
70 | ShowWarning(chkConfirmTrades);
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/Steam Desktop Authenticator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {0F37C513-9AF4-42C8-9CE9-F9B3BFA55E4E}
8 | WinExe
9 | Properties
10 | Steam_Desktop_Authenticator
11 | Steam Desktop Authenticator
12 | v4.7.2
13 | 512
14 | true
15 | false
16 |
17 |
18 |
19 | publish\
20 | true
21 | Disk
22 | false
23 | Foreground
24 | 7
25 | Days
26 | false
27 | false
28 | true
29 | 0
30 | 0.2.2.%2a
31 | false
32 | true
33 |
34 |
35 | false
36 |
37 |
38 |
39 |
40 |
41 |
42 | true
43 | bin\x64\Debug\
44 | DEBUG;TRACE
45 | full
46 | x64
47 | prompt
48 | MinimumRecommendedRules.ruleset
49 | true
50 |
51 |
52 | bin\x64\Release\
53 |
54 |
55 | true
56 | none
57 | x64
58 | prompt
59 | MinimumRecommendedRules.ruleset
60 | true
61 | .pdb
62 |
63 |
64 | true
65 | bin\Debug\
66 |
67 |
68 | full
69 | x86
70 | prompt
71 | MinimumRecommendedRules.ruleset
72 | true
73 | Auto
74 |
75 |
76 | bin\Release\
77 |
78 |
79 | true
80 | pdbonly
81 | x86
82 | prompt
83 | MinimumRecommendedRules.ruleset
84 | true
85 | Auto
86 | true
87 | false
88 | .pdb
89 |
90 |
91 | icon.ico
92 |
93 |
94 |
95 | packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll
96 |
97 |
98 | packages\Microsoft.Win32.Registry.5.0.0\lib\net461\Microsoft.Win32.Registry.dll
99 |
100 |
101 | packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll
102 |
103 |
104 | packages\protobuf-net.3.2.16\lib\net462\protobuf-net.dll
105 |
106 |
107 | packages\protobuf-net.Core.3.2.16\lib\net462\protobuf-net.Core.dll
108 |
109 |
110 | packages\SteamKit2.2.5.0-Beta.1\lib\netstandard2.0\SteamKit2.dll
111 |
112 |
113 |
114 | packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
115 |
116 |
117 | packages\System.Collections.Immutable.7.0.0\lib\net462\System.Collections.Immutable.dll
118 |
119 |
120 |
121 | packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
122 |
123 |
124 |
125 | packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
126 |
127 |
128 | packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
129 |
130 |
131 | packages\System.Security.AccessControl.5.0.0\lib\net461\System.Security.AccessControl.dll
132 |
133 |
134 | packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 | Component
149 |
150 |
151 | Form
152 |
153 |
154 | ConfirmationFormWeb.cs
155 |
156 |
157 |
158 | Form
159 |
160 |
161 | CaptchaForm.cs
162 |
163 |
164 | Form
165 |
166 |
167 | ImportAccountForm.cs
168 |
169 |
170 | Form
171 |
172 |
173 | InputForm.cs
174 |
175 |
176 | Form
177 |
178 |
179 | ListInputForm.cs
180 |
181 |
182 | Form
183 |
184 |
185 | LoginForm.cs
186 |
187 |
188 |
189 | Form
190 |
191 |
192 | MainForm.cs
193 |
194 |
195 |
196 |
197 |
198 | Form
199 |
200 |
201 | PhoneInputForm.cs
202 |
203 |
204 |
205 |
206 | Form
207 |
208 |
209 | SettingsForm.cs
210 |
211 |
212 | Form
213 |
214 |
215 | TradePopupForm.cs
216 |
217 |
218 |
219 | Form
220 |
221 |
222 | WelcomeForm.cs
223 |
224 |
225 | CaptchaForm.cs
226 |
227 |
228 | ConfirmationFormWeb.cs
229 |
230 |
231 | ImportAccountForm.cs
232 |
233 |
234 | InputForm.cs
235 |
236 |
237 | ListInputForm.cs
238 |
239 |
240 | LoginForm.cs
241 |
242 |
243 | MainForm.cs
244 |
245 |
246 | PhoneInputForm.cs
247 |
248 |
249 | SettingsForm.cs
250 |
251 |
252 | TradePopupForm.cs
253 |
254 |
255 | WelcomeForm.cs
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 | {5ad0934e-f6c4-4ae5-83af-c788313b2a87}
265 | SteamAuth
266 |
267 |
268 |
269 |
270 | False
271 | Microsoft .NET Framework 4.5.2 %28x86 and x64%29
272 | true
273 |
274 |
275 | False
276 | .NET Framework 3.5 SP1
277 | false
278 |
279 |
280 |
281 |
282 |
283 |
284 |
291 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/Steam Desktop Authenticator.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steam Desktop Authenticator", "Steam Desktop Authenticator.csproj", "{0F37C513-9AF4-42C8-9CE9-F9B3BFA55E4E}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SteamAuth", "..\lib\SteamAuth\SteamAuth\SteamAuth.csproj", "{5AD0934E-F6C4-4AE5-83AF-C788313B2A87}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|x86 = Debug|x86
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {0F37C513-9AF4-42C8-9CE9-F9B3BFA55E4E}.Debug|x86.ActiveCfg = Debug|x86
17 | {0F37C513-9AF4-42C8-9CE9-F9B3BFA55E4E}.Debug|x86.Build.0 = Debug|x86
18 | {0F37C513-9AF4-42C8-9CE9-F9B3BFA55E4E}.Release|x86.ActiveCfg = Release|x86
19 | {0F37C513-9AF4-42C8-9CE9-F9B3BFA55E4E}.Release|x86.Build.0 = Release|x86
20 | {5AD0934E-F6C4-4AE5-83AF-C788313B2A87}.Debug|x86.ActiveCfg = Debug|Any CPU
21 | {5AD0934E-F6C4-4AE5-83AF-C788313B2A87}.Debug|x86.Build.0 = Debug|Any CPU
22 | {5AD0934E-F6C4-4AE5-83AF-C788313B2A87}.Release|x86.ActiveCfg = Release|Any CPU
23 | {5AD0934E-F6C4-4AE5-83AF-C788313B2A87}.Release|x86.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/TradePopupForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Steam_Desktop_Authenticator
2 | {
3 | partial class TradePopupForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TradePopupForm));
32 | this.lblDesc = new System.Windows.Forms.Label();
33 | this.btnDeny = new System.Windows.Forms.Button();
34 | this.btnAccept = new System.Windows.Forms.Button();
35 | this.lblStatus = new System.Windows.Forms.Label();
36 | this.lblAccount = new System.Windows.Forms.Label();
37 | this.SuspendLayout();
38 | //
39 | // lblDesc
40 | //
41 | this.lblDesc.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
42 | this.lblDesc.Location = new System.Drawing.Point(12, 23);
43 | this.lblDesc.Name = "lblDesc";
44 | this.lblDesc.Size = new System.Drawing.Size(142, 38);
45 | this.lblDesc.TabIndex = 1;
46 | this.lblDesc.Text = "trade description";
47 | this.lblDesc.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
48 | //
49 | // btnDeny
50 | //
51 | this.btnDeny.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(192)))));
52 | this.btnDeny.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
53 | this.btnDeny.Location = new System.Drawing.Point(12, 87);
54 | this.btnDeny.Name = "btnDeny";
55 | this.btnDeny.Size = new System.Drawing.Size(69, 32);
56 | this.btnDeny.TabIndex = 2;
57 | this.btnDeny.Text = "Deny";
58 | this.btnDeny.UseVisualStyleBackColor = false;
59 | this.btnDeny.Click += new System.EventHandler(this.btnDeny_Click);
60 | //
61 | // btnAccept
62 | //
63 | this.btnAccept.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
64 | this.btnAccept.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
65 | this.btnAccept.Location = new System.Drawing.Point(87, 87);
66 | this.btnAccept.Name = "btnAccept";
67 | this.btnAccept.Size = new System.Drawing.Size(67, 32);
68 | this.btnAccept.TabIndex = 2;
69 | this.btnAccept.Text = "Accept";
70 | this.btnAccept.UseVisualStyleBackColor = false;
71 | this.btnAccept.Click += new System.EventHandler(this.btnAccept_Click);
72 | //
73 | // lblStatus
74 | //
75 | this.lblStatus.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
76 | this.lblStatus.Location = new System.Drawing.Point(0, 61);
77 | this.lblStatus.Name = "lblStatus";
78 | this.lblStatus.Size = new System.Drawing.Size(166, 19);
79 | this.lblStatus.TabIndex = 3;
80 | this.lblStatus.Text = "status";
81 | this.lblStatus.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
82 | //
83 | // lblAccount
84 | //
85 | this.lblAccount.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
86 | this.lblAccount.Location = new System.Drawing.Point(12, 0);
87 | this.lblAccount.Name = "lblAccount";
88 | this.lblAccount.Size = new System.Drawing.Size(142, 23);
89 | this.lblAccount.TabIndex = 4;
90 | this.lblAccount.Text = "account name";
91 | this.lblAccount.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
92 | //
93 | // TradePopupForm
94 | //
95 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
96 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
97 | this.ClientSize = new System.Drawing.Size(166, 131);
98 | this.Controls.Add(this.lblAccount);
99 | this.Controls.Add(this.lblStatus);
100 | this.Controls.Add(this.btnAccept);
101 | this.Controls.Add(this.btnDeny);
102 | this.Controls.Add(this.lblDesc);
103 | this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
104 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
105 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
106 | this.Name = "TradePopupForm";
107 | this.Text = "New confirmation";
108 | this.TopMost = true;
109 | this.Load += new System.EventHandler(this.TradePopupForm_Load);
110 | this.ResumeLayout(false);
111 |
112 | }
113 |
114 | #endregion
115 | private System.Windows.Forms.Label lblDesc;
116 | private System.Windows.Forms.Button btnDeny;
117 | private System.Windows.Forms.Button btnAccept;
118 | private System.Windows.Forms.Label lblStatus;
119 | private System.Windows.Forms.Label lblAccount;
120 | }
121 | }
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/TradePopupForm.cs:
--------------------------------------------------------------------------------
1 | using SteamAuth;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Data;
6 | using System.Drawing;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace Steam_Desktop_Authenticator
13 | {
14 | public partial class TradePopupForm : Form
15 | {
16 | private SteamGuardAccount acc;
17 | private List confirms = new List();
18 | private bool deny2, accept2;
19 |
20 | public TradePopupForm()
21 | {
22 | InitializeComponent();
23 | lblStatus.Text = "";
24 | }
25 |
26 | public SteamGuardAccount Account
27 | {
28 | get { return acc; }
29 | set { acc = value; lblAccount.Text = acc.AccountName; }
30 | }
31 |
32 | public Confirmation[] Confirmations
33 | {
34 | get { return confirms.ToArray(); }
35 | set { confirms = new List(value); }
36 | }
37 |
38 | private void TradePopupForm_Load(object sender, EventArgs e)
39 | {
40 | this.Location = (Point)Size.Subtract(Screen.GetWorkingArea(this).Size, this.Size);
41 | }
42 |
43 | private void btnAccept_Click(object sender, EventArgs e)
44 | {
45 | if (!accept2)
46 | {
47 | // Allow user to confirm first
48 | lblStatus.Text = "Press Accept again to confirm";
49 | btnAccept.BackColor = Color.FromArgb(128, 255, 128);
50 | accept2 = true;
51 | }
52 | else
53 | {
54 | lblStatus.Text = "Accepting...";
55 | acc.AcceptConfirmation(confirms[0]);
56 | confirms.RemoveAt(0);
57 | Reset();
58 | }
59 | }
60 |
61 | private void btnDeny_Click(object sender, EventArgs e)
62 | {
63 | if (!deny2)
64 | {
65 | lblStatus.Text = "Press Deny again to confirm";
66 | btnDeny.BackColor = Color.FromArgb(255, 255, 128);
67 | deny2 = true;
68 | }
69 | else
70 | {
71 | lblStatus.Text = "Denying...";
72 | acc.DenyConfirmation(confirms[0]);
73 | confirms.RemoveAt(0);
74 | Reset();
75 | }
76 | }
77 |
78 | private void Reset()
79 | {
80 | deny2 = false;
81 | accept2 = false;
82 | btnAccept.BackColor = Color.FromArgb(192, 255, 192);
83 | btnDeny.BackColor = Color.FromArgb(255, 255, 192);
84 |
85 | btnAccept.Text = "Accept";
86 | btnDeny.Text = "Deny";
87 | lblAccount.Text = "";
88 | lblStatus.Text = "";
89 |
90 | if (confirms.Count == 0)
91 | {
92 | this.Hide();
93 | }
94 | else
95 | {
96 | //TODO: Re-add confirmation description support to SteamAuth.
97 | lblDesc.Text = "Confirmation";
98 | }
99 | }
100 |
101 | public void Popup()
102 | {
103 | Reset();
104 | this.Show();
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/UserFormAuthenticator.cs:
--------------------------------------------------------------------------------
1 | using SteamAuth;
2 | using SteamKit2.Authentication;
3 | using System.Threading.Tasks;
4 | using System.Windows.Forms;
5 |
6 | namespace Steam_Desktop_Authenticator
7 | {
8 | internal class UserFormAuthenticator : IAuthenticator
9 | {
10 | private SteamGuardAccount account;
11 | private int deviceCodesGenerated = 0;
12 |
13 | public UserFormAuthenticator(SteamGuardAccount account)
14 | {
15 | this.account = account;
16 | }
17 |
18 | public Task AcceptDeviceConfirmationAsync()
19 | {
20 | return Task.FromResult(false);
21 | }
22 |
23 | public async Task GetDeviceCodeAsync(bool previousCodeWasIncorrect)
24 | {
25 | // If a code fails wait 30 seconds for a new one to regenerate
26 | if (previousCodeWasIncorrect)
27 | {
28 | // After 2 tries tell the user that there seems to be an issue
29 | if (deviceCodesGenerated > 2)
30 | MessageBox.Show("There seems to be an issue logging into your account with these two factor codes. Are you sure SDA is still your authenticator?");
31 |
32 | await Task.Delay(30000);
33 | }
34 |
35 | string deviceCode;
36 |
37 | if (account == null)
38 | {
39 | MessageBox.Show("This account already has an authenticator linked. You must remove that authenticator to add SDA as your authenticator.", "Steam Login", MessageBoxButtons.OK, MessageBoxIcon.Error);
40 | return null;
41 | }
42 | else
43 | {
44 | deviceCode = await account.GenerateSteamGuardCodeAsync();
45 | deviceCodesGenerated++;
46 | }
47 |
48 | return deviceCode;
49 | }
50 |
51 | public Task GetEmailCodeAsync(string email, bool previousCodeWasIncorrect)
52 | {
53 | string message = "Enter the code sent to your email:";
54 | if (previousCodeWasIncorrect)
55 | {
56 | message = "The code you provided was invalid. Enter the code sent to your email:";
57 | }
58 |
59 | InputForm emailForm = new InputForm(message);
60 | emailForm.ShowDialog();
61 | return Task.FromResult(emailForm.txtBox.Text);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/WelcomeForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Steam_Desktop_Authenticator
2 | {
3 | partial class WelcomeForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(WelcomeForm));
32 | this.label1 = new System.Windows.Forms.Label();
33 | this.btnImportConfig = new System.Windows.Forms.Button();
34 | this.label2 = new System.Windows.Forms.Label();
35 | this.btnJustStart = new System.Windows.Forms.Button();
36 | this.SuspendLayout();
37 | //
38 | // label1
39 | //
40 | this.label1.Font = new System.Drawing.Font("Segoe UI", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
41 | this.label1.Location = new System.Drawing.Point(12, 9);
42 | this.label1.Name = "label1";
43 | this.label1.Size = new System.Drawing.Size(366, 73);
44 | this.label1.TabIndex = 0;
45 | this.label1.Text = "Welcome to\r\nSteam Desktop Authenticator";
46 | this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
47 | //
48 | // btnImportConfig
49 | //
50 | this.btnImportConfig.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
51 | this.btnImportConfig.Location = new System.Drawing.Point(12, 134);
52 | this.btnImportConfig.Name = "btnImportConfig";
53 | this.btnImportConfig.Size = new System.Drawing.Size(366, 51);
54 | this.btnImportConfig.TabIndex = 1;
55 | this.btnImportConfig.Text = "I already setup Steam Desktop Authenticator in another location on this PC and I " +
56 | "want to import its account(s).\r\n";
57 | this.btnImportConfig.UseVisualStyleBackColor = true;
58 | this.btnImportConfig.Click += new System.EventHandler(this.btnImportConfig_Click);
59 | //
60 | // label2
61 | //
62 | this.label2.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
63 | this.label2.Location = new System.Drawing.Point(12, 86);
64 | this.label2.Name = "label2";
65 | this.label2.Size = new System.Drawing.Size(366, 37);
66 | this.label2.TabIndex = 2;
67 | this.label2.Text = "Select an item to get started:";
68 | this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
69 | //
70 | // btnJustStart
71 | //
72 | this.btnJustStart.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
73 | this.btnJustStart.Location = new System.Drawing.Point(12, 191);
74 | this.btnJustStart.Name = "btnJustStart";
75 | this.btnJustStart.Size = new System.Drawing.Size(366, 52);
76 | this.btnJustStart.TabIndex = 4;
77 | this.btnJustStart.Text = "This is my first time and \r\nI just want to sign into my Steam Account(s).";
78 | this.btnJustStart.UseVisualStyleBackColor = true;
79 | this.btnJustStart.Click += new System.EventHandler(this.btnJustStart_Click);
80 | //
81 | // WelcomeForm
82 | //
83 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
84 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
85 | this.ClientSize = new System.Drawing.Size(390, 255);
86 | this.Controls.Add(this.btnJustStart);
87 | this.Controls.Add(this.label2);
88 | this.Controls.Add(this.btnImportConfig);
89 | this.Controls.Add(this.label1);
90 | this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
91 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
92 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
93 | this.MaximizeBox = false;
94 | this.Name = "WelcomeForm";
95 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
96 | this.Text = "Steam Desktop Authenticator";
97 | this.ResumeLayout(false);
98 |
99 | }
100 |
101 | #endregion
102 |
103 | private System.Windows.Forms.Label label1;
104 | private System.Windows.Forms.Button btnImportConfig;
105 | private System.Windows.Forms.Label label2;
106 | private System.Windows.Forms.Button btnJustStart;
107 | }
108 | }
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/WelcomeForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Data;
6 | using System.Drawing;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace Steam_Desktop_Authenticator
13 | {
14 | public partial class WelcomeForm : Form
15 | {
16 | private Manifest man;
17 |
18 | public WelcomeForm()
19 | {
20 | InitializeComponent();
21 | man = Manifest.GetManifest();
22 | }
23 |
24 | private void btnJustStart_Click(object sender, EventArgs e)
25 | {
26 | // Mark as not first run anymore
27 | man.FirstRun = false;
28 | man.Save();
29 |
30 | showMainForm();
31 | }
32 |
33 | private void btnImportConfig_Click(object sender, EventArgs e)
34 | {
35 | // Let the user select the config dir
36 | FolderBrowserDialog folderBrowser = new FolderBrowserDialog();
37 | folderBrowser.Description = "Select the folder of your old Steam Desktop Authenticator install";
38 | DialogResult userClickedOK = folderBrowser.ShowDialog();
39 |
40 | if (userClickedOK == DialogResult.OK)
41 | {
42 | string path = folderBrowser.SelectedPath;
43 | string pathToCopy = null;
44 |
45 | if (Directory.Exists(path + "/maFiles"))
46 | {
47 | // User selected the root install dir
48 | pathToCopy = path + "/maFiles";
49 | }
50 | else if (File.Exists(path + "/manifest.json"))
51 | {
52 | // User selected the maFiles dir
53 | pathToCopy = path;
54 | }
55 | else
56 | {
57 | // Could not find either.
58 | MessageBox.Show("This folder does not contain either a manifest.json or an maFiles folder.\nPlease select the location where you had Steam Desktop Authenticator installed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
59 | return;
60 | }
61 |
62 | // Copy the contents of the config dir to the new config dir
63 | string currentPath = Manifest.GetExecutableDir();
64 |
65 | // Create config dir if we don't have it
66 | if (!Directory.Exists(currentPath + "/maFiles"))
67 | {
68 | Directory.CreateDirectory(currentPath + "/maFiles");
69 | }
70 |
71 | // Copy all files from the old dir to the new one
72 | foreach (string newPath in Directory.GetFiles(pathToCopy, "*.*", SearchOption.AllDirectories))
73 | {
74 | File.Copy(newPath, newPath.Replace(pathToCopy, currentPath + "/maFiles"), true);
75 | }
76 |
77 | // Set first run in manifest
78 | try
79 | {
80 | man = Manifest.GetManifest(true);
81 | man.FirstRun = false;
82 | man.Save();
83 | }
84 | catch (ManifestParseException)
85 | {
86 | // Manifest file was corrupted, generate a new one.
87 | try
88 | {
89 | MessageBox.Show("Your settings were unexpectedly corrupted and were reset to defaults.", "Steam Desktop Authenticator", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
90 | man = Manifest.GenerateNewManifest(true);
91 | }
92 | catch (MaFileEncryptedException)
93 | {
94 | // An maFile was encrypted, we're fucked.
95 | MessageBox.Show("Sorry, but SDA was unable to recover your accounts since you used encryption.\nYou'll need to recover your Steam accounts by removing the authenticator.\nClick OK to view instructions.", "Steam Desktop Authenticator", MessageBoxButtons.OK, MessageBoxIcon.Error);
96 | System.Diagnostics.Process.Start(@"https://github.com/Jessecar96/SteamDesktopAuthenticator/wiki/Help!-I'm-locked-out-of-my-account");
97 | this.Close();
98 | return;
99 | }
100 | }
101 |
102 | // All done!
103 | MessageBox.Show("All accounts and settings have been imported! Click OK to continue.", "Import accounts", MessageBoxButtons.OK, MessageBoxIcon.Information);
104 | showMainForm();
105 | }
106 |
107 | }
108 |
109 | private void showMainForm()
110 | {
111 | this.Hide();
112 | new MainForm().Show();
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SteamDesktopAuthenticatorr/SteamDesktopAuthenticator/0f52174e4db3a75e52fda2f12ae1a4ee5cbbc71a/Steam Desktop Authenticator/icon.ico
--------------------------------------------------------------------------------
/Steam Desktop Authenticator/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SteamDesktopAuthenticatorr/SteamDesktopAuthenticator/0f52174e4db3a75e52fda2f12ae1a4ee5cbbc71a/icon.png
--------------------------------------------------------------------------------