KiCad PCB EDA Suite
Loading...
Searching...
No Matches
remote_login_server.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23#include <wx/tokenzr.h>
24#include <wx/uri.h>
25
26#include <remote_login_server.h>
27
28
29wxDEFINE_EVENT( EVT_REMOTE_SYMBOL_LOGIN_RESULT, wxCommandEvent );
30
31REMOTE_LOGIN_SERVER::REMOTE_LOGIN_SERVER( wxEvtHandler* aOwner, const wxString& aRedirectUrl ) :
32 m_owner( aOwner ),
33 m_redirectUrl( aRedirectUrl ),
34 m_port( 0 ),
35 m_done( false )
36{
37 m_timeout.SetOwner( this );
38 Bind( wxEVT_TIMER, &REMOTE_LOGIN_SERVER::OnTimeout, this, m_timeout.GetId() );
39}
40
42{
43 m_timeout.Stop();
44 Unbind( wxEVT_SOCKET, &REMOTE_LOGIN_SERVER::OnSocketEvent, this );
45 Unbind( wxEVT_TIMER, &REMOTE_LOGIN_SERVER::OnTimeout, this, m_timeout.GetId() );
46 Shutdown();
47 m_timeout.SetOwner( nullptr );
48}
49
51{
52 wxIPV4address addr;
53 addr.AnyAddress();
54 addr.Service( 0 );
55
56 std::unique_ptr<wxSocketServer> server =
57 std::make_unique<wxSocketServer>( addr, wxSOCKET_REUSEADDR );
58
59 if( !server->IsOk() )
60 return false;
61
62 server->SetEventHandler( *this );
63 server->SetNotify( wxSOCKET_CONNECTION_FLAG );
64 server->Notify( true );
65
66 wxIPV4address local;
67 server->GetLocal( local );
68 m_port = local.Service();
69
70 Bind( wxEVT_SOCKET, &REMOTE_LOGIN_SERVER::OnSocketEvent, this );
71
72 m_server = std::move( server );
73 m_timeout.StartOnce( 120000 );
74 return m_port != 0;
75}
76
77void REMOTE_LOGIN_SERVER::OnSocketEvent( wxSocketEvent& aEvent )
78{
79 if( !m_server || aEvent.GetSocketEvent() != wxSOCKET_CONNECTION )
80 return;
81
82 std::unique_ptr<wxSocketBase> client( m_server->Accept( false ) );
83
84 if( !client )
85 return;
86
87 HandleClient( client.get() );
88}
89
90void REMOTE_LOGIN_SERVER::OnTimeout( wxTimerEvent& aEvent )
91{
92 wxUnusedVar( aEvent );
93 Finish( false, wxString() );
94}
95
96void REMOTE_LOGIN_SERVER::HandleClient( wxSocketBase* aClient )
97{
98 if( !aClient )
99 return;
100
101 aClient->SetTimeout( 5 );
102 aClient->SetFlags( wxSOCKET_NONE );
103
104 std::string request;
105 request.reserve( 512 );
106
107 char buffer[512];
108
109 while( aClient->IsConnected() )
110 {
111 if( !aClient->WaitForRead( 1, 0 ) )
112 break;
113
114 aClient->Read( buffer, sizeof( buffer ) );
115 size_t count = aClient->LastCount();
116
117 if( count == 0 )
118 break;
119
120 request.append( buffer, count );
121
122 if( request.find( "\r\n\r\n" ) != std::string::npos || request.size() > 4096 )
123 break;
124 }
125
126 SendHttpResponse( aClient );
127
128 wxString requestWx = wxString::FromUTF8( request.data(), request.size() );
129 int endOfLine = requestWx.Find( wxS( "\r\n" ) );
130 wxString requestLine = endOfLine == wxNOT_FOUND ? requestWx : requestWx.Mid( 0, endOfLine );
131
132 wxString userId = ExtractUserId( requestLine );
133 Finish( !userId.IsEmpty(), userId );
134}
135
136wxString REMOTE_LOGIN_SERVER::ExtractUserId( const wxString& aRequestLine ) const
137{
138 wxStringTokenizer tokenizer( aRequestLine, wxS( " " ) );
139
140 if( !tokenizer.HasMoreTokens() )
141 return wxString();
142
143 tokenizer.GetNextToken();
144
145 if( !tokenizer.HasMoreTokens() )
146 return wxString();
147
148 wxString path = tokenizer.GetNextToken();
149 int queryPos = path.Find( '?' );
150
151 if( queryPos == wxNOT_FOUND )
152 return wxString();
153
154 wxString query = path.Mid( queryPos + 1 );
155 wxStringTokenizer queryTokenizer( query, wxS( "&" ) );
156
157 while( queryTokenizer.HasMoreTokens() )
158 {
159 wxString pair = queryTokenizer.GetNextToken();
160 int eqPos = pair.Find( '=' );
161
162 if( eqPos == wxNOT_FOUND )
163 continue;
164
165 wxString name = pair.Left( eqPos );
166 wxString value = pair.Mid( eqPos + 1 );
167
168 if( name == wxS( "user_id" ) )
169 return wxURI::Unescape( value );
170 }
171
172 return wxString();
173}
174
175void REMOTE_LOGIN_SERVER::SendHttpResponse( wxSocketBase* aClient )
176{
177 if( !aClient )
178 return;
179
180 wxString redirect = m_redirectUrl;
181
182 if( redirect.IsEmpty() )
183 redirect = wxS( "about:blank" );
184
185 wxString html;
186 html << wxS( "<!DOCTYPE html><html><head>" )
187 << wxS( "<meta http-equiv=\"refresh\" content=\"0;url=" ) << redirect << wxS( "\">" )
188 << wxS( "</head><body>" )
189 << wxS( "<script>window.location.href = '" ) << redirect << wxS( "';</script>" )
190 << wxS( "<p>Login successful. Redirecting...</p>" )
191 << wxS( "</body></html>" );
192
193 wxScopedCharBuffer body = html.ToUTF8();
194
195 wxString response;
196 response << wxS( "HTTP/1.1 200 OK\r\n" )
197 << wxS( "Content-Type: text/html; charset=utf-8\r\n" )
198 << wxS( "Access-Control-Allow-Origin: *\r\n" )
199 << wxS( "Cache-Control: no-store\r\n" )
200 << wxS( "Connection: close\r\n" )
201 << wxS( "Content-Length: " ) << body.length() << wxS( "\r\n\r\n" );
202
203 wxScopedCharBuffer header = response.ToUTF8();
204
205 aClient->Write( header.data(), header.length() );
206 aClient->Write( body.data(), body.length() );
207 aClient->Close();
208}
209
210void REMOTE_LOGIN_SERVER::Finish( bool aSuccess, const wxString& aUserId )
211{
212 if( m_done )
213 return;
214
215 m_done = true;
216 m_timeout.Stop();
217
218 wxCommandEvent evt( EVT_REMOTE_SYMBOL_LOGIN_RESULT );
219 evt.SetInt( aSuccess ? 1 : 0 );
220 evt.SetString( aUserId );
221 wxQueueEvent( m_owner, evt.Clone() );
222
223 Shutdown();
224}
225
227{
228 if( m_server )
229 {
230 m_server->Notify( false );
231 m_server.reset();
232 }
233}
const char * name
REMOTE_LOGIN_SERVER(wxEvtHandler *aOwner, const wxString &aRedirectUrl)
std::unique_ptr< wxSocketServer > m_server
void SendHttpResponse(wxSocketBase *aClient)
void HandleClient(wxSocketBase *aClient)
void Finish(bool aSuccess, const wxString &aUserId)
void OnSocketEvent(wxSocketEvent &aEvent)
wxString ExtractUserId(const wxString &aRequestLine) const
void OnTimeout(wxTimerEvent &aEvent)
wxDEFINE_EVENT(EVT_REMOTE_SYMBOL_LOGIN_RESULT, wxCommandEvent)
std::string path