Skip to content
Snippets Groups Projects
Commit 2b266aa4 authored by ARMINGAUD Robin's avatar ARMINGAUD Robin
Browse files

Merge branch 'dev_robin' into 'main'

V1.0.1

See merge request !2
parents fdfb6ab6 7785164c
No related branches found
No related tags found
1 merge request!2V1.0.1
Pipeline #4372 failed
Showing
with 304 additions and 164 deletions
buildscript {
ext.kotlin_version = '1.3.50'
ext.kotlin_version = '1.6.0'
repositories {
google()
mavenCentral()
......
-----BEGIN CERTIFICATE-----
MIIESTCCAzGgAwIBAgITBn+UV4WH6Kx33rJTMlu8mYtWDTANBgkqhkiG9w0BAQsF
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
b24gUm9vdCBDQSAxMB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjEL
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENB
IDFCMQ8wDQYDVQQDEwZBbWF6b24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDCThZn3c68asg3Wuw6MLAd5tES6BIoSMzoKcG5blPVo+sDORrMd4f2AbnZ
cMzPa43j4wNxhplty6aUKk4T1qe9BOwKFjwK6zmxxLVYo7bHViXsPlJ6qOMpFge5
blDP+18x+B26A0piiQOuPkfyDyeR4xQghfj66Yo19V+emU3nazfvpFA+ROz6WoVm
B5x+F2pV8xeKNR7u6azDdU5YVX1TawprmxRC1+WsAYmz6qP+z8ArDITC2FMVy2fw
0IjKOtEXc/VfmtTFch5+AfGYMGMqqvJ6LcXiAhqG5TI+Dr0RtM88k+8XUBCeQ8IG
KuANaL7TiItKZYxK1MMuTJtV9IblAgMBAAGjggE7MIIBNzASBgNVHRMBAf8ECDAG
AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUWaRmBlKge5WSPKOUByeW
dFv5PdAwHwYDVR0jBBgwFoAUhBjMhTTsvAyUlC4IWZzHshBOCggwewYIKwYBBQUH
AQEEbzBtMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5yb290Y2ExLmFtYXpvbnRy
dXN0LmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NydC5yb290Y2ExLmFtYXpvbnRy
dXN0LmNvbS9yb290Y2ExLmNlcjA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3Js
LnJvb3RjYTEuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTEuY3JsMBMGA1UdIAQMMAow
CAYGZ4EMAQIBMA0GCSqGSIb3DQEBCwUAA4IBAQCFkr41u3nPo4FCHOTjY3NTOVI1
59Gt/a6ZiqyJEi+752+a1U5y6iAwYfmXss2lJwJFqMp2PphKg5625kXg8kP2CN5t
6G7bMQcT8C8xDZNtYTd7WPD8UZiRKAJPBXa30/AbwuZe0GaFEQ8ugcYQgSn+IGBI
8/LwhBNTZTUVEWuCUUBVV18YtbAiPq3yXqMB48Oz+ctBWuZSkbvkNodPLamkB2g1
upRyzQ7qDn1X8nn8N8V7YJ6y68AtkHcNSRAnpTitxBKjtKPISLMVCx7i4hncxHZS
yLyKQXhw2W2Xs0qLeC1etA+jTGDK4UfLeC0SF7FSi8o5LL21L8IzApar2pR/
-----END CERTIFICATE-----
......@@ -20,33 +20,13 @@ class MyApp extends StatelessWidget {
return MaterialApp(
title: 'AppScale',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blueGrey,
),
routes: {
LoginPage.routeName: (context) => LoginPage(),
DirectoryPage.routeName: (context) => const DirectoryPage(directory: [
Profile(
"Brad",
"Pitt",
"https://media.gqmagazine.fr/photos/6082bd46e24bc2c55a7e1c4f/1:1/w_120",
"William Bradley Pitt (born December 18, 1963) is an American actor and film producer."),
Profile(
"Georges",
"Clooney",
"https://fr.web.img6.acsta.net/pictures/16/05/12/17/04/136865.jpg",
"George Timothy Clooney (born May 6, 1961) is an American actor and filmmaker. He is the recipient of numerous accolades, including a British Academy Film Award, four Golden Globe Awards, and two Academy Awards, one for his acting and the other as a producer."),
])
},
home: LoginPage(),
);
}
}
......@@ -8,8 +8,8 @@ class Profile {
this.firstName, this.lastName, this.thumbnailPath, this.biography);
Profile.fromJson(Map<String, dynamic> json)
: firstName = json['first_name'],
lastName = json['last_name'],
thumbnailPath = json["profile_picture"],
: firstName = json['firstname'],
lastName = json['lastname'],
thumbnailPath = json["picture"],
biography = json["biography"];
}
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_application_1/models/profile.dart';
import 'package:flutter_application_1/views/directory_page.dart';
import 'package:flutter_application_1/views/login_page.dart';
import 'package:http/http.dart' as http;
Future<void> DirectoryMethod(BuildContext context) async {
var response = await http.get(
Uri.parse('https://serverscale.herokuapp.com/directory_page'),
headers: <String, String>{}
);
var resp = jsonDecode(response.body);
List<Profile> list = <Profile>[];
for (var item in resp){
list.add(Profile(item['firstname'], item['lastname'] , 'secret', 'secret'));
}
Navigator.push(context, MaterialPageRoute(builder :(context) => DirectoryPage(directory : list)));
}
\ No newline at end of file
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_application_1/views/login_page.dart';
import 'package:http/http.dart' as http;
Future<void> LogoutMethod(BuildContext context) async {
Navigator.pushReplacement(context, MaterialPageRoute(builder :(context) => const LoginPage()));
await http.get(
Uri.parse('https://serverscale.herokuapp.com/logout'),
headers: <String, String>{}
);
}
\ No newline at end of file
import 'dart:convert';
import 'package:encrypt/encrypt.dart';
import 'package:encrypt/encrypt_io.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_application_1/models/profile.dart';
import 'package:flutter_application_1/views/directory_page.dart';
import 'package:flutter_application_1/views/login_page.dart';
import 'package:http/http.dart' as http;
import 'dart:io';
import 'package:pointycastle/asymmetric/api.dart';
import 'package:ssl_pinning_plugin/ssl_pinning_plugin.dart';
Future<SecurityContext> get globalContext async {
final sslCert1 = await rootBundle.load('/certificate.pem');
SecurityContext sc = SecurityContext(withTrustedRoots: false);
sc.setTrustedCertificatesBytes(sslCert1.buffer.asInt8List());
return sc;}
// ignore: unused_import
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_application_1/models/profile.dart';
// ignore: unused_import
import 'package:flutter_application_1/services/logout.dart';
import 'package:flutter_application_1/views/profile_page.dart';
class DirectoryPage extends StatelessWidget {
final List<Profile> directory;
static const routeName = '/directory-page';
......@@ -16,21 +15,13 @@ class DirectoryPage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Annuaire"),
),
title: const Text("Directory"),
actions: <Widget>[IconButton(icon: const Icon(Icons.power_settings_new_rounded), onPressed: () {LogoutMethod(context);})]),
body: ListView.builder(
itemCount: directory.length,
itemBuilder: (BuildContext context, int position) {
Profile item = directory.elementAt(position);
return ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfilePage(profile: item)),
);
},
trailing: const Icon(Icons.arrow_right),
title: Text("${item.firstName} ${item.lastName}"),
);
}),
......
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_application_1/models/profile.dart';
import 'package:flutter_application_1/services/secure.dart';
import 'package:flutter_application_1/views/directory_page.dart';
import 'package:flutter_application_1/views/profile_page.dart';
import 'package:http/http.dart' as http;
import 'package:ssl_pinning_plugin/ssl_pinning_plugin.dart';
Future<void> LoginMethod(String username, String password) async {
class LoginPage extends StatefulWidget {
static const routeName = '/login-page';
const LoginPage({Key? key}) : super(key: key);
@override
State<LoginPage> createState() => _LoginPageState();
}
class _PiningSslData {
String serverURL = 'https://serverscale.herokuapp.com/logout';
HttpMethod httpMethod = HttpMethod.Get;
Map<String, String> headerHttp = Map();
String allowedSHAFingerprint = '99:E0:DA:5F:A7:92:41:75:1B:D5:41:FD:A5:DA:EA:F7:E4:A7:0A:72';
int timeout = 60;
late SHA sha = SHA.SHA1;
}
class _LoginPageState extends State<LoginPage> {
late String pseudo;
late String password;
_PiningSslData _data = _PiningSslData();
final _formKey = GlobalKey<FormState>();
@override
initState() {
super.initState();
}
Future<void> LoginMethod(String username, String password, BuildContext context) async {
var response = await http.post(
Uri.parse('https://127.0.0.1:5000/login'),
Uri.parse('https://serverscale.herokuapp.com/login'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
......@@ -14,51 +49,72 @@ Future<void> LoginMethod(String username, String password) async {
<String, String>{"username": username, "password": password}),
);
if (response.statusCode == 200) {
// If the server did return a 200 response,
// then parse the JSON.
print('ok');
} else {
// If the server did not return a 200 response,
// then throw an exception.
throw Exception('Failed to create album.');
}
}
if (response.body=="authentication error: try again"){
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text("Incorrect username or password."),
));
class Album {
final String username;
final String password;
}
else {
try{
String checkMsg = await SslPinningPlugin.check(
serverURL : 'https://serverscale.herokuapp.com/logout',
httpMethod : HttpMethod.Get,
headerHttp : Map(),
allowedSHAFingerprints :['99 E0 DA 5F A7 92 41 75 1B D5 41 FD A5 DA EA F7 E4 A7 0A 72'],
timeout : 60,
sha : SHA.SHA1);
const Album({required this.username, required this.password});
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
username: json['username'],
password: json['password'],
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(checkMsg),
duration: Duration(seconds: 1),
backgroundColor: Colors.green,
),
);
if (checkMsg.toString() != 'CONNECTION_SECURE'){
return;
}
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => ProfilePage(profile : Profile.fromJson(jsonDecode(response.body)))));}
catch(e){
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(e.toString()),
duration: Duration(seconds: 1),
backgroundColor: Colors.red,
),
);
}
class LoginPage extends StatefulWidget {
static const routeName = '/login-page';
const LoginPage({Key? key}) : super(key: key);
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
late String pseudo;
late String password;
final _formKey = GlobalKey<FormState>();
}
// If the server did return a 200 response,
// then parse the JSON.
else {
// If the server did not return a 200 response,
// then throw an exception.
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text("Error : unable to connect to server"),
));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Login')),
body: Padding(
padding: const EdgeInsets.all(60),
padding: const EdgeInsets.all(30),
child: Center(
child: Form(
key: _formKey,
......@@ -101,7 +157,7 @@ class _LoginPageState extends State<LoginPage> {
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
LoginMethod(pseudo, password);
LoginMethod(pseudo, password,context);
}
},
style: ElevatedButton.styleFrom(
......
import 'package:flutter/material.dart';
import 'package:flutter_application_1/models/profile.dart';
import 'package:flutter_application_1/services/directory.dart';
import 'package:flutter_application_1/services/logout.dart';
import 'package:flutter_application_1/views/login_page.dart';
import 'package:http/http.dart' as http;
class ProfilePage extends StatelessWidget {
final Profile profile;
......@@ -8,7 +12,9 @@ class ProfilePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Profile"),),
appBar: AppBar(title: const Text("Profile"),
actions: <Widget>[IconButton(icon: const Icon(Icons.power_settings_new_rounded), onPressed: () {LogoutMethod(context);}),
IconButton(icon: const Icon(Icons.home_filled), onPressed: () {DirectoryMethod(context);})]),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
......
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0"
asn1lib:
dependency: transitive
description:
name: asn1lib
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.9.0"
version: "2.8.2"
boolean_selector:
dependency: transitive
description:
......@@ -42,7 +56,21 @@ packages:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.16.0"
version: "1.15.0"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.2"
cupertino_icons:
dependency: "direct main"
description:
......@@ -50,13 +78,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
encrypt:
dependency: "direct main"
description:
name: encrypt
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.1"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.2.0"
flutter:
dependency: "direct main"
description: flutter
......@@ -88,6 +123,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.4"
lints:
dependency: transitive
description:
......@@ -108,7 +150,7 @@ packages:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
version: "0.1.3"
meta:
dependency: transitive
description:
......@@ -122,7 +164,14 @@ packages:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
version: "1.8.0"
pointycastle:
dependency: transitive
description:
name: pointycastle
url: "https://pub.dartlang.org"
source: hosted
version: "3.6.0"
sky_engine:
dependency: transitive
description: flutter
......@@ -134,7 +183,14 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.2"
version: "1.8.1"
ssl_pinning_plugin:
dependency: "direct main"
description:
name: ssl_pinning_plugin
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
stack_trace:
dependency: transitive
description:
......@@ -169,7 +225,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.9"
version: "0.4.8"
typed_data:
dependency: transitive
description:
......@@ -183,6 +239,7 @@ packages:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
version: "2.1.1"
sdks:
dart: ">=2.17.0-0 <3.0.0"
dart: ">=2.16.0-100.0.dev <3.0.0"
flutter: ">=2.0.0"
......@@ -35,6 +35,8 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
encrypt: ^5.0.1
ssl_pinning_plugin: ^2.0.0
dev_dependencies:
flutter_test:
......
import 'package:flutter/material.dart';
import 'package:flutter_application_1/models/profile.dart';
import 'package:flutter_application_1/views/directory_page.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Display profile list', (WidgetTester tester) async {
// Build our app and trigger a frame.
const List<Profile> directory = [
Profile("Brad","Pitt","https://media.gqmagazine.fr/photos/6082bd46e24bc2c55a7e1c4f/1:1/w_120", "William Bradley Pitt (born December 18, 1963) is an American actor and film producer."),
Profile("Georges","Clooney","",""),
];
await tester.pumpWidget(const MaterialApp(home: DirectoryPage(directory: directory,),));
expect(find.text('Keyser Söze'), findsNothing);
expect(find.text('Brad Pitt'), findsOneWidget);
expect(find.text('Georges Clooney'), findsOneWidget);
});
}
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_application_1/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
import os
from flask_login import current_user, login_user, LoginManager,login_required,logout_user
from flask import Flask, jsonify, request
from werkzeug.security import check_password_hash
from database.database import db, init_database
import database.models as models
app = Flask(__name__)
login = LoginManager(app)
login.session_protection = "strong"
# Setup the secret key and the environment
app.config.update(SECRET_KEY=str(os.urandom(64)),
ENV='development')
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///database/database.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db.init_app(app)
......@@ -13,16 +20,29 @@ with app.app_context():
init_database()
models.populate_database()
@login.user_loader
def load_user(id):
return User.query.get(int(id))
@app.route('/')
def hello_world():
return login()
@app.route('/login', methods=['POST', 'GET'])
@app.route('/login', methods=['POST'])
def login():
username = request.form.get('username')
password = request.form.get('password')
if current_user.is_authenticated :
return jsonify({
"firstname": current_user.firstname,
"lastname": current_user.lastname,
"picture": current_user.picture,
"biography": current_user.biography
})
json = request.get_json()
username = json['username']
password = json['password']
user = models.User.query.filter_by(username=username).first()
# check if the user actually exists
......@@ -30,36 +50,33 @@ def login():
if not user or not check_password_hash(user.password, password):
return "authentication error: try again"
# if the above check passes, then we know the user has the right credentials
users = models.User.query.all()
data = []
for user in users:
data.append({
elif user and check_password_hash(user.password,password):
login_user(user)
return jsonify({
"firstname": user.firstname,
"lastname": user.lastname,
"picture": user.picture,
"biography": user.biography
})
return jsonify(data)
'''
@app.route('/for_tests')
def populate():
db.drop_all()
db.create_all()
models.populate_database()
@app.route('/directory_page')
def directory_page():
json = request.get_json()
users = models.User.query.all()
data = []
for user in users:
data.append({
"firstname": user.firstname,
"lastname": user.lastname,
"picture": user.picture,
"biography": user.biography
})
return jsonify(data)
'''
@app.route('/logout')
def logout():
logout_user()
return "Logout"
port = int(os.environ.get("PORT", 5000)) # <-----
app.run(host='0.0.0.0', port=port)
if __name__ == '__main__':
......
SECRET_KEY="|vn\xe4_P\xa9d\xa0\x1aC\xa7\x04\xd0\xcd\x97\xd1\xd5\x99c\x93\x14\x93\x91$\xe0\xac\x8c9t\xd01\xc5k\xa0\xd5X\xf2\xad\xbaR\x92\xa2\xf5:\xd3N\xa0G\xcdN\x81\xf0\x9cb^\xe3v}\x0b\xd7K\xcc5"
\ No newline at end of file
......@@ -11,7 +11,8 @@ class User(UserMixin, db.Model):
"""
__tablename__ = 'user'
username = db.Column(db.String, primary_key=True)
id = db.Column(db.Integer,primary_key=True)
username = db.Column(db.String)
password = db.Column(db.String) # as a sha256
lastname = db.Column(db.String)
firstname = db.Column(db.String)
......@@ -20,6 +21,7 @@ class User(UserMixin, db.Model):
def populate_database():
user = User(
id=1,
username="test",
password=generate_password_hash("a", method='sha256'),
lastname="Bidule",
......@@ -29,6 +31,7 @@ def populate_database():
)
db.session.add(user)
user2 = User(
id=2,
username="Brad",
password=generate_password_hash("a", method='sha256'),
lastname="Pitt",
......@@ -38,6 +41,7 @@ def populate_database():
)
db.session.add(user2)
user3 = User(
id=3,
username="George",
password=generate_password_hash("a", method='sha256'),
lastname="Clooney",
......
......@@ -3,3 +3,5 @@ Flask_Login==0.5.0
Flask_SQLAlchemy==2.5.1
Werkzeug==2.0.2
gunicorn==20.1.0
flask_login
cryptography
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment