about summary refs log tree commit diff
path: root/MatrixRoomUtils.Web/Pages/LoginPage.razor
blob: b6f244d2067ed002bb28e9a0283b5d3d657fe4b6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
@page "/Login"
@using System.Text.Json
@using System.Text.Json.Serialization
@using LibMatrix
@inject ILocalStorageService LocalStorage
@inject IJSRuntime JsRuntime
<h3>Login</h3>
<hr/>

<span style="display: block;">
    <label>User ID:</label>
    <span>@@</span><!--
    --><FancyTextBox @bind-Value="@newRecordInput.Username"></FancyTextBox><!--
    --><span>:</span><!--
    --><FancyTextBox @bind-Value="@newRecordInput.Homeserver"></FancyTextBox>
</span>
<span style="display: block;">
    <label>Password:</label>
    <FancyTextBox @bind-Value="@newRecordInput.Password" IsPassword="true"></FancyTextBox>
</span>
<span style="display: block">
    <label>Proxy (<a href="https://cgit.rory.gay/matrix/MxApiExtensions.git">MxApiExtensions</a> or similar):</label>
    <FancyTextBox @bind-Value="@newRecordInput.Proxy"></FancyTextBox>
</span>
<br/>
<LinkButton OnClick="@AddRecord">Add account to queue</LinkButton>
<LinkButton OnClick="@(() => Login(newRecordInput))">Log in</LinkButton>
<br/>
<br/>

<h4>Import from TSV</h4>
<hr/>
<span>Import credentials from a TSV (Tab Separated Values) file</span><br/>
<span>Columns: username, homeserver, password, proxy</span><br/>
<span>Keep in mind there is no column header!</span><br/>
<br/>
<InputFile OnChange="@FileChanged" accept=".tsv"></InputFile>
<br/>
<br/>

<table border="1">
    <thead style="border-bottom: 1px solid white;">
        <th style="min-width: 150px; text-align: center; border-right: 1px solid white;">Username</th>
        <th style="min-width: 150px; text-align: center; border-right: 1px solid white;">Homeserver</th>
        <th style="min-width: 150px; text-align: center; border-right: 1px solid white;">Password</th>
        <th style="min-width: 150px; text-align: center; border-right: 1px solid white;">Proxy</th>
        <th style="min-width: 150px; text-align: center;">Actions</th>
    </thead>
    @foreach (var record in records) {
        var r = record;
        <tr style="background-color: @(LoggedInSessions.Any(x => x.UserId == $"@{r.Username}:{r.Homeserver}" && x.Proxy == r.Proxy) ? "green" : "unset")">
            <td style="border-width: 1px;">
                <FancyTextBox @bind-Value="@r.Username"></FancyTextBox>
            </td>
            <td style="border-width: 1px;">
                <FancyTextBox @bind-Value="@r.Homeserver"></FancyTextBox>
            </td>
            <td style="border-width: 1px;">
                <FancyTextBox @bind-Value="@r.Password" IsPassword="true"></FancyTextBox>
            </td>
            <td style="border-width: 1px;">
                <FancyTextBox @bind-Value="@r.Proxy"></FancyTextBox>
            </td>
            <td style="border-width: 1px;">
                <a role="button" @onclick="() => records.Remove(r)">Remove</a>
            </td>
        </tr>
        @if (r.Exception is MatrixException me) {
            <tr>
                <td style="border-width: 1px;">Exception:</td>
                <td style="border-width: 1px;">@me.ErrorCode</td>
                <td style="border-width: 1px;" colspan="3">@me.Error</td>
            </tr>
        }
        else if (r.Exception is { } e) {
            <tr>
                <td style="border-width: 1px;">Exception:</td>
                <td style="border-width: 1px;" colspan="4">@e.Message</td>
            </tr>
        }
    }
</table>
<br/>
<LinkButton OnClick="@LoginAll">Log in</LinkButton>


@code {
    readonly List<LoginStruct> records = new();
    private LoginStruct newRecordInput = new();

    List<UserAuth>? LoggedInSessions { get; set; } = new();

    async Task LoginAll() {
        var loginTasks = records.Select(Login);
        await Task.WhenAll(loginTasks);
    }

    async Task Login(LoginStruct record) {
        if (!records.Contains(record)) 
            records.Add(record);
        if (LoggedInSessions.Any(x => x.UserId == $"@{record.Username}:{record.Homeserver}" && x.Proxy == record.Proxy)) return;
        StateHasChanged();
        try {
            var result = new UserAuth(await hsProvider.Login(record.Homeserver, record.Username, record.Password, record.Proxy)) {
                Proxy = record.Proxy
            };
            if (result == null) {
                Console.WriteLine($"Failed to login to {record.Homeserver} as {record.Username}!");
                return;
            }

            Console.WriteLine($"Obtained access token for {result.UserId}!");

            await MRUStorage.AddToken(result);
            LoggedInSessions = await MRUStorage.GetAllTokens();
        }
        catch (Exception e) {
            Console.WriteLine($"Failed to login to {record.Homeserver} as {record.Username}!");
            Console.WriteLine(e);
            record.Exception = e;
        }

        StateHasChanged();
    }

    private async Task FileChanged(InputFileChangeEventArgs obj) {
        LoggedInSessions = await MRUStorage.GetAllTokens();
        Console.WriteLine(JsonSerializer.Serialize(obj, new JsonSerializerOptions {
            WriteIndented = true
        }));
        await using var rs = obj.File.OpenReadStream();
        using var sr = new StreamReader(rs);
        var tsvData = await sr.ReadToEndAsync();
        records.Clear();
        foreach (var line in tsvData.Split('\n')) {
            string?[] parts = line.Split('\t');
            if (parts.Length < 3)
                continue;
            string? via = parts.Length > 3 ? parts[3] : null;
            records.Add(new() { Homeserver = parts[0], Username = parts[1], Password = parts[2], Proxy = via });
        }
    }

    private async Task AddRecord() {
        LoggedInSessions = await MRUStorage.GetAllTokens();
        records.Add(newRecordInput);
        newRecordInput = new();
    }

    private class LoginStruct {
        public string? Homeserver { get; set; } = "";
        public string? Username { get; set; } = "";
        public string? Password { get; set; } = "";
        public string? Proxy { get; set; }
        
        [JsonIgnore]
        internal Exception? Exception { get; set; }
    }

}