Skip to content

Commit 5d2bf27

Browse files
committed
Add new ssid support.
1 parent 6cabcca commit 5d2bf27

File tree

10 files changed

+219
-186
lines changed

10 files changed

+219
-186
lines changed

samples/TsinghuaNet/Program.vb

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,30 @@ Module Program
2424
Console.Error.WriteLine("Exception occured: {0}", ex.Message)
2525
Return
2626
End Try
27-
Dim helper As IConnect = Nothing
27+
28+
Dim username As String = command.Username
29+
Dim password As String = If(command.Password, String.Empty)
30+
Dim helper As IConnect = CreateHelper(username, password, command.Host)
31+
If helper Is Nothing Then
32+
Console.Error.WriteLine("Invalid host.")
33+
Return
34+
End If
2835
If command.Login Then
29-
If command.Logout Then
30-
Console.Error.WriteLine("Cannot login and logout at the same time!")
31-
Return
32-
End If
33-
Dim username As String = command.Username
3436
If username Is Nothing Then
3537
Console.Error.WriteLine("Please input username.")
3638
Return
3739
End If
38-
Dim password As String = If(command.Password, String.Empty)
39-
helper = CreateHelper(username, password, command.Host)
40-
If helper Is Nothing Then
41-
Console.Error.WriteLine("Invalid host.")
40+
If command.Logout Then
41+
Console.Error.WriteLine("Cannot login and logout at the same time!")
4242
Return
4343
End If
4444
Login(helper).Wait()
4545
ElseIf command.Logout Then
46-
helper = CreateHelper(Nothing, Nothing, command.Host)
47-
If helper Is Nothing Then
48-
Console.Error.WriteLine("Invalid host.")
46+
If username Is Nothing Then
47+
Console.Error.WriteLine("Please input username.")
4948
Return
5049
End If
51-
Logout(helper, command.Username).Wait()
50+
Logout(helper).Wait()
5251
End If
5352
If command.Flux Then
5453
If helper Is Nothing Then
@@ -78,18 +77,14 @@ Module Program
7877
End Function
7978
Async Function Login(helper As IConnect) As Task
8079
Try
81-
Console.WriteLine(Await helper.LoginAsync())
80+
Console.WriteLine((Await helper.LoginAsync()).Message)
8281
Catch ex As Exception
8382
Console.Error.WriteLine("Exception occured: {0}", ex.Message)
8483
End Try
8584
End Function
86-
Async Function Logout(helper As IConnect, username As String) As Task
85+
Async Function Logout(helper As IConnect) As Task
8786
Try
88-
If username Is Nothing Then
89-
Console.WriteLine(Await helper.LogoutAsync())
90-
Else
91-
Console.WriteLine(Await helper.LogoutAsync(username))
92-
End If
87+
Console.WriteLine((Await helper.LogoutAsync()).Message)
9388
Catch ex As Exception
9489
Console.Error.WriteLine("Exception occured: {0}", ex.Message)
9590
End Try

samples/TsinghuaNet/TsinghuaNetCommand.vb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Class TsinghuaNetCommand
1111
Public Property Logout As Boolean
1212
<[Option]("f"c, "flux", HelpText:="Option to get flux of the user online")>
1313
Public Property Flux As Boolean
14-
<[Option]("u"c, "username", HelpText:="Username to login, required when -i")>
14+
<[Option]("u"c, "username", HelpText:="Username to login, required when -i or -o")>
1515
Public Property Username As String
1616
<[Option]("p"c, "password", HelpText:="Password to login")>
1717
Public Property Password As String

src/Berrysoft.Tsinghua.Net/AuthHelper.cs

Lines changed: 65 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
using System;
2-
using System.Collections.Generic;
1+
using System.Collections.Generic;
2+
using System.Json;
33
using System.Net.Http;
4-
using System.Text.RegularExpressions;
54
using System.Threading.Tasks;
65

76
namespace Berrysoft.Tsinghua.Net
@@ -14,8 +13,7 @@ public abstract class AuthHelper : NetHelperBase, IConnect
1413
private const string LogUriBase = "https://auth{0}.tsinghua.edu.cn/cgi-bin/srun_portal";
1514
private const string FluxUriBase = "https://auth{0}.tsinghua.edu.cn/rad_user_info.php";
1615
private const string ChallengeUriBase = "https://auth{0}.tsinghua.edu.cn/cgi-bin/get_challenge?username={{0}}&double_stack=1&ip&callback=callback";
17-
private const string LogoutData = "action=logout";
18-
private const string LogoutUserData = "action=logout&username={0}";
16+
private static readonly int[] AcIds = new int[] { 1, 25, 33, 35 };
1917
private readonly string LogUri;
2018
private readonly string FluxUri;
2119
private readonly string ChallengeUri;
@@ -61,66 +59,95 @@ internal AuthHelper(string username, string password, HttpClient client, int ver
6159
/// Login to the network.
6260
/// </summary>
6361
/// <returns>The response of the website.</returns>
64-
public async Task<string> LoginAsync() => await PostAsync(LogUri, await GetLoginDataAsync());
62+
public async Task<LogResponse> LoginAsync()
63+
{
64+
LogResponse response = null;
65+
foreach (int ac_id in AcIds)
66+
{
67+
response = LogResponse.ParseFromAuth(await PostAsync(LogUri, await GetLoginDataAsync(ac_id)));
68+
if (response.Succeed)
69+
break;
70+
}
71+
return response;
72+
}
73+
6574
/// <summary>
6675
/// Logout from the network.
6776
/// </summary>
6877
/// <returns>The response of the website.</returns>
69-
public Task<string> LogoutAsync() => PostAsync(LogUri, LogoutData);
70-
/// <summary>
71-
/// Logout from the network with the specified username.
72-
/// When a user logged in through <see cref="AuthHelper"/> and logged out through <see cref="NetHelper"/>,
73-
/// he should call this method with his username explicitly, or he can't logout.
74-
/// </summary>
75-
/// <param name="username">The specified username.</param>
76-
/// <returns>The response of the website.</returns>
77-
public Task<string> LogoutAsync(string username) => PostAsync(LogUri, string.Format(LogoutUserData, username));
78+
public async Task<LogResponse> LogoutAsync()
79+
{
80+
LogResponse response = null;
81+
foreach (int ac_id in AcIds)
82+
{
83+
response = LogResponse.ParseFromAuth(await PostAsync(LogUri, await GetLogoutDataAsync(ac_id)));
84+
if (response.Succeed)
85+
break;
86+
}
87+
return response;
88+
}
89+
7890
/// <summary>
7991
/// Get information of the user online.
8092
/// </summary>
8193
/// <returns>An instance of <see cref="FluxUser"/> class of the current user.</returns>
8294
public async Task<FluxUser> GetFluxAsync() => FluxUser.Parse(await PostAsync(FluxUri));
8395

84-
private static readonly Regex ChallengeRegex = new Regex(@"""challenge"":""(.*?)""");
8596
/// <summary>
8697
/// Get "challenge" to encode the password.
8798
/// </summary>
8899
/// <returns>The content of the website.</returns>
89100
private async Task<string> GetChallengeAsync()
90101
{
91102
string result = await GetAsync(string.Format(ChallengeUri, Username));
92-
Match match = ChallengeRegex.Match(result);
93-
return match.Groups[1].Value;
103+
JsonValue json = JsonValue.Parse(result.Substring(9, result.Length - 10));
104+
return json["challenge"];
94105
}
95106

96-
private Dictionary<string, string> logDataDictionary;
97-
private const string LoginInfoJson = "{{\"ip\": \"\", \"acid\": \"1\", \"enc_ver\": \"srun_bx1\", \"username\": \"{0}\", \"password\": \"{1}\"}}";
98-
private const string ChkSumData = "{0}{1}{0}{2}{0}1{0}{0}200{0}1{0}{3}";
107+
private const string LoginInfoJson = "{{\"username\": \"{0}\", \"password\": \"{1}\", \"ip\": \"\", \"acid\": \"{2}\", \"enc_ver\": \"srun_bx1\"}}";
108+
private const string ChkSumData = "{0}{1}{0}{2}{0}{4}{0}{0}200{0}1{0}{3}";
99109
/// <summary>
100110
/// Get login data with username, password and "challenge".
101111
/// </summary>
102112
/// <returns>A dictionary contains the data.</returns>
103-
private async Task<Dictionary<string, string>> GetLoginDataAsync()
113+
private async Task<Dictionary<string, string>> GetLoginDataAsync(int ac_id)
104114
{
105-
//const string passwordMD5 = "5e543256c480ac577d30f76f9120eb74";
106115
string token = await GetChallengeAsync();
107116
string passwordMD5 = CryptographyHelper.GetHMACMD5(token);
108-
if (logDataDictionary == null)
117+
string info = "{SRBX1}" + CryptographyHelper.Base64Encode(CryptographyHelper.XEncode(string.Format(LoginInfoJson, Username, Password, ac_id), token));
118+
return new Dictionary<string, string>
109119
{
110-
logDataDictionary = new Dictionary<string, string>
111-
{
112-
["ac_id"] = "1",
113-
["double_stack"] = "1",
114-
["n"] = "200",
115-
["type"] = "1"
116-
};
117-
}
118-
logDataDictionary["action"] = "login";
119-
logDataDictionary["password"] = "{MD5}" + passwordMD5;
120-
logDataDictionary["info"] = "{SRBX1}" + CryptographyHelper.Base64Encode(CryptographyHelper.XEncode(string.Format(LoginInfoJson, Username, Password), token));
121-
logDataDictionary["username"] = Username;
122-
logDataDictionary["chksum"] = CryptographyHelper.GetSHA1(string.Format(ChkSumData, token, Username, passwordMD5, logDataDictionary["info"]));
123-
return logDataDictionary;
120+
["action"] = "login",
121+
["ac_id"] = ac_id.ToString(),
122+
["double_stack"] = "1",
123+
["n"] = "200",
124+
["type"] = "1",
125+
["username"] = Username,
126+
["password"] = "{MD5}" + passwordMD5,
127+
["info"] = info,
128+
["chksum"] = CryptographyHelper.GetSHA1(string.Format(ChkSumData, token, Username, passwordMD5, info, ac_id)),
129+
["callback"] = "callback"
130+
};
131+
}
132+
133+
private const string LogoutInfoJson = "{{\"username\": \"{0}\", \"ip\": \"\", \"acid\": \"{1}\", \"enc_ver\": \"srun_bx1\"}}";
134+
private const string LogoutChkSumData = "{0}{1}{0}{3}{0}{0}200{0}1{0}{2}";
135+
private async Task<Dictionary<string, string>> GetLogoutDataAsync(int ac_id)
136+
{
137+
string token = await GetChallengeAsync();
138+
string info = "{SRBX1}" + CryptographyHelper.Base64Encode(CryptographyHelper.XEncode(string.Format(LogoutInfoJson, Username, ac_id), token));
139+
return new Dictionary<string, string>
140+
{
141+
["action"] = "logout",
142+
["ac_id"] = ac_id.ToString(),
143+
["double_stack"] = "1",
144+
["n"] = "200",
145+
["type"] = "1",
146+
["username"] = Username,
147+
["info"] = info,
148+
["chksum"] = CryptographyHelper.GetSHA1(string.Format(LogoutChkSumData, token, Username, info, ac_id)),
149+
["callback"] = "callback"
150+
};
124151
}
125152
}
126153
/// <summary>

src/Berrysoft.Tsinghua.Net/Berrysoft.Tsinghua.Net.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
1212
</PropertyGroup>
1313

14+
<ItemGroup>
15+
<PackageReference Include="System.Json" Version="4.5.0" />
16+
</ItemGroup>
17+
1418
<ItemGroup>
1519
<Reference Include="System.Net.Http" Condition="'$(TargetFramework)'=='net48'" />
1620
</ItemGroup>

src/Berrysoft.Tsinghua.Net/CryptographyHelper.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Security.Cryptography;
1+
using System.Security.Cryptography;
52
using System.Text;
63

74
namespace Berrysoft.Tsinghua.Net
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System;
2+
3+
namespace Berrysoft.Tsinghua.Net
4+
{
5+
/// <summary>
6+
/// A simple class represents the current user online.
7+
/// </summary>
8+
public class FluxUser
9+
{
10+
/// <summary>
11+
/// Initializes a new instance of the <see cref="FluxUser"/> class.
12+
/// </summary>
13+
/// <param name="username">Username of the user.</param>
14+
/// <param name="flux">Flux used by the user this month.</param>
15+
/// <param name="onlineTime">Online time used this time of the user.</param>
16+
/// <param name="balance">The network balance of the user.</param>
17+
public FluxUser(string username, long flux, TimeSpan onlineTime, decimal balance)
18+
{
19+
Username = username;
20+
Flux = flux;
21+
OnlineTime = onlineTime;
22+
Balance = balance;
23+
}
24+
/// <summary>
25+
/// Username of the user.
26+
/// </summary>
27+
public string Username { get; }
28+
/// <summary>
29+
/// Flux used by the user this month.
30+
/// </summary>
31+
public long Flux { get; }
32+
/// <summary>
33+
/// Online time used this time of the user.
34+
/// </summary>
35+
public TimeSpan OnlineTime { get; }
36+
/// <summary>
37+
/// The network balance of the user.
38+
/// </summary>
39+
public decimal Balance { get; }
40+
41+
internal static FluxUser Parse(string fluxstr)
42+
{
43+
string[] r = fluxstr.Split(',');
44+
if (string.IsNullOrWhiteSpace(r[0]))
45+
{
46+
return null;
47+
}
48+
else
49+
{
50+
return new FluxUser(
51+
r[0],
52+
long.Parse(r[6]),
53+
TimeSpan.FromSeconds(long.Parse(r[2]) - long.Parse(r[1])),
54+
decimal.Parse(r[11]));
55+
}
56+
}
57+
}
58+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System;
2+
using System.Json;
3+
4+
namespace Berrysoft.Tsinghua.Net
5+
{
6+
/// <summary>
7+
/// The response of Login or Logout.
8+
/// </summary>
9+
public class LogResponse
10+
{
11+
/// <summary>
12+
/// Shows whether the command is succeed.
13+
/// </summary>
14+
public bool Succeed { get; }
15+
/// <summary>
16+
/// The formatted response message.
17+
/// </summary>
18+
public string Message { get; }
19+
20+
/// <summary>
21+
/// Initialize a new instance of <see cref="LogResponse"/> class.
22+
/// </summary>
23+
/// <param name="succeed">Whether the command is succeed.</param>
24+
/// <param name="message">The formatted response message.</param>
25+
public LogResponse(bool succeed, string message)
26+
{
27+
Succeed = succeed;
28+
Message = message;
29+
}
30+
31+
internal static LogResponse ParseFromNet(string response)
32+
{
33+
return new LogResponse(response == "Login is successful.", response);
34+
}
35+
36+
internal static LogResponse ParseFromAuth(string response)
37+
{
38+
try
39+
{
40+
string jsonstr = response.Substring(9, response.Length - 10);
41+
JsonValue json = JsonValue.Parse(jsonstr);
42+
return new LogResponse(json["error"] == "ok", $"error: {json["error"]}\nerror_msg: {json["error_msg"]}");
43+
}
44+
catch (Exception)
45+
{
46+
return new LogResponse(false, response);
47+
}
48+
}
49+
50+
internal static LogResponse ParseFromUsereg(string response)
51+
{
52+
return new LogResponse(response == "ok", response);
53+
}
54+
}
55+
}

0 commit comments

Comments
 (0)