Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions lib/application/auth/auth_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,26 @@ import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import 'package:ltemanager2/domain/auth/i_auth_facade.dart';
import 'package:shared_preferences/shared_preferences.dart';

part 'auth_bloc.freezed.dart';
part 'auth_event.dart';
part 'auth_state.dart';

@injectable
class AuthBloc extends Bloc<AuthEvent, AuthState> {
final IAuthFacade _authFacade;
final IAuthFacade _huaweiAuthFacade;
final IAuthFacade _zteAuthFacade;
final SharedPreferences _preferences;

AuthBloc(this._authFacade) : super(const AuthState.initial()) {
AuthBloc(
this._huaweiAuthFacade,
@Named('RouterZteAuthFacade') this._zteAuthFacade,
this._preferences,
) : super(const AuthState.initial()) {
on<SignOut>(
(event, emit) async {
final result = await _authFacade.signOut();
final result = await _getFacade().signOut();
emit(
result.fold(
(_) => const AuthState.authenticated(),
Expand All @@ -25,7 +32,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
},
);
on<AuthCheckRequested>((event, emit) async {
final userOption = await _authFacade.isSignedIn();
final userOption = await _getFacade().isSignedIn();

debugPrint(userOption.toString());

Expand All @@ -37,4 +44,9 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
);
});
}

IAuthFacade _getFacade() {
final manufacturer = _preferences.getString('_manufacturer') ?? 'huawei';
return manufacturer == 'zte' ? _zteAuthFacade : _huaweiAuthFacade;
}
}
17 changes: 14 additions & 3 deletions lib/application/auth/sign_in_form/sign_in_form_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,23 @@ import 'package:injectable/injectable.dart';
import 'package:ltemanager2/domain/auth/auth_failure.dart';
import 'package:ltemanager2/domain/auth/i_auth_facade.dart';
import 'package:ltemanager2/domain/auth/value_objects.dart';
import 'package:shared_preferences/shared_preferences.dart';

part 'sign_in_form_bloc.freezed.dart';
part 'sign_in_form_event.dart';
part 'sign_in_form_state.dart';

@injectable
class SignInFormBloc extends Bloc<SignInFormEvent, SignInFormState> {
final IAuthFacade _authFacade;
final IAuthFacade _huaweiAuthFacade;
final IAuthFacade _zteAuthFacade;
final SharedPreferences _preferences;

SignInFormBloc(this._authFacade) : super(SignInFormState.initial()) {
SignInFormBloc(
this._huaweiAuthFacade,
@Named('RouterZteAuthFacade') this._zteAuthFacade,
this._preferences,
) : super(SignInFormState.initial()) {
on<UsernameChanged>(
(event, emit) {
emit(
Expand Down Expand Up @@ -62,7 +69,11 @@ class SignInFormBloc extends Bloc<SignInFormEvent, SignInFormState> {
),
);

failureOrSuccess = await _authFacade.signInWithEmailAndPassword(
final manufacturer =
_preferences.getString('_manufacturer') ?? 'huawei';
final facade =
manufacturer == 'zte' ? _zteAuthFacade : _huaweiAuthFacade;
failureOrSuccess = await facade.signInWithEmailAndPassword(
url: state.ipAddress,
username: state.username,
password: state.password,
Expand Down
1 change: 1 addition & 0 deletions lib/domain/auth/manufacturer.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
enum Manufacturer { huawei, zte }
1 change: 1 addition & 0 deletions lib/infrastructure/auth/router_huawei_auth_facade.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import 'package:ltemanager2/infrastructure/core/router_huawei_api.dart';
import 'package:chopper/chopper.dart';
import 'package:shared_preferences/shared_preferences.dart';

@Named("HuaweiRouterAuthFacade")
@LazySingleton(as: IAuthFacade)
class RouterHuaweiAuthFacade implements IAuthFacade {
final HuaweiRouterApi _api;
Expand Down
86 changes: 86 additions & 0 deletions lib/infrastructure/auth/router_zte_auth_facade.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import 'dart:convert';

import 'package:crypto/crypto.dart';
import 'package:dartz/dartz.dart';
import 'package:http/http.dart' as http;
import 'package:injectable/injectable.dart';
import 'package:ltemanager2/domain/auth/auth_failure.dart';
import 'package:ltemanager2/domain/auth/i_auth_facade.dart';
import 'package:ltemanager2/domain/auth/value_objects.dart';
import 'package:shared_preferences/shared_preferences.dart';

@Named("ZTERouterAuthFacade")
@LazySingleton(as: IAuthFacade)
class RouterZteAuthFacade implements IAuthFacade {
final SharedPreferences _sharedPreferences;

RouterZteAuthFacade(this._sharedPreferences);

Future<void> _setRouterURL(String url) async {
await _sharedPreferences.setString('_baseUrl', url);
}

@override
Future<Either<AuthFailure, Unit>> signInWithEmailAndPassword({
required IPAddress url,
required Username username,
required Password password,
}) async {
final urlStr = url.value.getOrElse(() => '');
await _setRouterURL(urlStr);
final passwordStr = password.value.getOrElse(() => '');

try {
final ldResp = await http.get(
Uri.parse('$urlStr/goform/goform_get_cmd_process?isTest=false&cmd=LD'),
headers: {'referer': urlStr},
);
if (ldResp.statusCode != 200) {
return left(const AuthFailure.serverError());
}
final ld =
(jsonDecode(ldResp.body) as Map<String, dynamic>)['LD'] as String;

final first =
sha256.convert(utf8.encode(passwordStr)).toString().toUpperCase();
final second =
sha256.convert(utf8.encode('$first$ld')).toString().toUpperCase();

final loginResp = await http.get(
Uri.parse(
'$urlStr/goform/goform_set_cmd_process?isTest=false&goformId=LOGIN&password=$second'),
headers: {'referer': urlStr},
);

if (loginResp.statusCode == 200) {
final body = jsonDecode(loginResp.body) as Map<String, dynamic>;
if (body['result'] == '0') {
await _sharedPreferences.setString(
'_sessionCookie',
loginResp.headers['set-cookie'] ?? '',
);
return right(unit);
}
return left(const AuthFailure.invalidEmailAndPasswordCombination());
}
return left(const AuthFailure.serverError());
} catch (_) {
return left(const AuthFailure.serverError());
}
}

@override
Future<Either<AuthFailure, Unit>> isSignedIn() async {
final cookie = _sharedPreferences.getString('_sessionCookie') ?? '';
if (cookie.isEmpty) {
return left(const AuthFailure.notAuthenticated());
}
return right(unit);
}

@override
Future<Either<AuthFailure, Unit>> signOut() async {
await _sharedPreferences.setString('_sessionCookie', '');
return right(unit);
}
}
47 changes: 31 additions & 16 deletions lib/injection.config.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 40 additions & 9 deletions lib/presentation/pages/sign_in/widgets/sign_in_form.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,19 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:ltemanager2/application/auth/auth_bloc.dart';
import 'package:ltemanager2/application/auth/sign_in_form/sign_in_form_bloc.dart';
import 'package:ltemanager2/presentation/routes/router.gr.dart';
import 'package:ltemanager2/domain/auth/manufacturer.dart';
import 'package:ltemanager2/utilities/SharedPreferencesFunctions.dart';

class SignInForm extends StatelessWidget {
class SignInForm extends StatefulWidget {
const SignInForm({Key? key}) : super(key: key);

@override
State<SignInForm> createState() => _SignInFormState();
}

class _SignInFormState extends State<SignInForm> {
Manufacturer _manufacturer = Manufacturer.huawei;

@override
Widget build(BuildContext context) {
return BlocConsumer<SignInFormBloc, SignInFormState>(
Expand Down Expand Up @@ -256,16 +265,37 @@ class SignInForm extends StatelessWidget {
),
(_) => null,
),
onEditingComplete: () =>
TextInput.finishAutofillContext(),
),
),
),
],
onEditingComplete: () =>
TextInput.finishAutofillContext(),
),
),
const Spacer(),
const SizedBox(height: 8),
),
const SizedBox(height: 8),
DropdownButton<Manufacturer>(
value: _manufacturer,
onChanged: (val) {
if (val != null) {
setState(() {
_manufacturer = val;
});
}
},
items: const [
DropdownMenuItem(
value: Manufacturer.huawei,
child: Text('Huawei'),
),
DropdownMenuItem(
value: Manufacturer.zte,
child: Text('ZTE'),
),
],
),
],
),
),
const Spacer(),
const SizedBox(height: 8),
OutlinedButton(
style: ButtonStyle(
minimumSize: MaterialStateProperty.all(const Size(250, 50)),
Expand All @@ -279,6 +309,7 @@ class SignInForm extends StatelessWidget {
),
),
onPressed: () {
saveSharedPref('_manufacturer', _manufacturer.name);
context.read<SignInFormBloc>().add(
const SignInFormEvent
.signInWithEmailAndPasswordPressed(),
Expand Down