diff --git a/.gitignore b/.gitignore index a2f3a19..db5f872 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,6 @@ .packages # server.dart compiled executable server +server.exe # Conventional directory for build output. build/ diff --git a/bin/server.dart b/bin/server.dart index b279a0d..eacc415 100755 --- a/bin/server.dart +++ b/bin/server.dart @@ -16,7 +16,7 @@ final _router = Router() ..post('/user/account', API.createAccount) // vrai post // PUT ..put('/user/master-password', API.changeMasterPassword) - ..put('/user/password-file', API.uploadPasswordDb) + ..post('/user/password-file', API.uploadPasswordDb) ..put('/user/change-mail', API.changeMail) // DELETE ..delete('/user/account', API.deleteAccount); @@ -49,7 +49,7 @@ void main(List args) async { final handler = Pipeline().addMiddleware(logRequests()).addHandler(_router); // For running in containers, we respect the PORT environment variable. - final port = int.parse(Platform.environment['PORT'] ?? '8080'); + final port = int.parse(Platform.environment['PORT'] ?? '8989'); final server = await serve(handler, ip, port); print('Server listening on port ${server.port}'); } diff --git a/lib/api/api.dart b/lib/api/api.dart index 6efc9af..d652720 100644 --- a/lib/api/api.dart +++ b/lib/api/api.dart @@ -1,3 +1,4 @@ +import 'dart:io'; import 'package:passworld_api/db_to_api.dart'; import 'package:postgres/postgres.dart'; import 'package:shelf/shelf.dart'; @@ -23,7 +24,7 @@ class API { if (await checkRequiredFields(required, body)) { try { - await AccountsToPostgres.selectHashById(body[required[0]]); + await AccountsToPostgres.selectHashByMail(body[required[0]]); } catch (e) { return Response(404, body: 'Not Found'); // no hash found -> 404 (Not Found) @@ -67,8 +68,8 @@ class API { if (await checkRequiredFields(required, body)) { // List twofa = body[required[3]]; try { - await AccountsToPostgres.create(body[required[0]], body[required[1]], - body[required[2]] /*, twofa*/); + await AccountsToPostgres.createAccount(body[required[0]], + body[required[1]], body[required[2]] /*, twofa*/); } catch (e) { return Response(409, body: 'Account already existing'); // 409 (Conflict) @@ -86,17 +87,49 @@ class API { // Update master password static Response changeMasterPassword(Request req) { - return Response.ok("master password chnaged"); + return Response.ok("master password changed"); } // Update mail - static Response changeMail(Request req) { - return Response.ok("master password chnaged"); + static Future changeMail(Request req) async { + final List required = ["email", "newMail"]; + final body = await bodyToJson(req); + + if (await checkRequiredFields(required, body)) { + try { + await AccountsToPostgres.updateMail( + body[required[0]], body[required[1]]); + } catch (e) { + return Response(403, + body: 'This is not the good password'); // 403 (Forbidden) + } + return Response(201, + body: 'user\'s mail succesfully changed'); // 201 (Created) + } else { + return Response.badRequest(body: 'Bad request'); // 400 (Bad Request) + } } // Upload sqlite password file - static Response uploadPasswordDb(Request req) { - return Response.ok(""); + static Future uploadPasswordDb(Request req) async { + sleep(Duration(seconds: 20)); + Stream> fileStream = + await req.read(); // await is needed even if IDE say no + List> tmpFile = await fileStream.toList(); + List fileAsBytes = tmpFile[0]; + + File file = File("./passfile"); + file.writeAsBytes(fileAsBytes); + + print(await file.stat()); + + //File test = File("./haha.yu"); + //await test.writeAsBytes(listBytes); + //print(await test.stat()); + + //print("Bytes: $listBytes"); + //print("Lenght: $size"); + return Response.ok("API: file received"); } /*---------------| diff --git a/lib/database/accounts_to_postgres.dart b/lib/database/accounts_to_postgres.dart index 5bb72d7..945062a 100644 --- a/lib/database/accounts_to_postgres.dart +++ b/lib/database/accounts_to_postgres.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:ffi'; import 'dart:io'; import 'package:postgres/postgres.dart'; @@ -9,16 +8,16 @@ class AccountsToPostgres { // username: 'pass', password: '1p2a3s4s5'); /* Dev RemRem */ - // static final connection = PostgreSQLConnection("localhost", 5432, 'passworld', - // username: 'hel', password: ''); + static final connection = PostgreSQLConnection("localhost", 5432, 'passworld', + username: 'hel', password: ''); /* Production */ - static final connection = PostgreSQLConnection( - Platform.environment["DB_SERVER"]!, - 5432, - Platform.environment["DB_DATABASE"]!, - username: Platform.environment["DB_USER"], - password: Platform.environment["DB_PASSWORD"]); + // static final connection = PostgreSQLConnection( + // Platform.environment["DB_SERVER"]!, + // 5432, + // Platform.environment["DB_DATABASE"]!, + // username: Platform.environment["DB_USER"], + // password: Platform.environment["DB_PASSWORD"]); AccountsToPostgres() { //initConnection(); @@ -38,20 +37,32 @@ class AccountsToPostgres { static Future createAccountTable() async { await openConnection(); - await connection - .query( - "CREATE TABLE IF NOT EXISTS \"Account\"(id TEXT PRIMARY KEY,hash TEXT NOT NULL,salt TEXT NOT NULL,twofa VARCHAR(50)[],passwords INTEGER[])") - .then((value) { - print("🟦 Account Table Created"); - }); + await connection.query(""" + CREATE TABLE IF NOT EXISTS \"Account\"( + id INT PRIMARY KEY, + mail TEXT NOT NULL UNIQUE, + hash TEXT NOT NULL, + salt TEXT NOT NULL, + twofa VARCHAR(50)[], + password_file INTEGER[] + )"""); + + await connection.query(""" + CREATE SEQUENCE IF NOT EXISTS plus1id + INCREMENT 1 + START 1"""); + + print("🟦 Account Table Created"); } // Add support for twoFa if needed - static Future create(String email, String hash, - String salt /*, List twoFaStr*/) async { - await connection.query("INSERT INTO \"Account\" VALUES(@id,@hash,@salt)", + static Future createAccount( + String mail, String hash, String salt /*, List twoFaStr*/) async { + await checkMailAlreadyExist(mail); // TODO: throw execption if != null + await connection.query( + "INSERT INTO \"Account\" VALUES(nextval('plus1id'),@mail,@hash,@salt)", substitutionValues: { - "id": email, + "mail": mail, "hash": hash, "salt": salt /*, "twofa": twoFaStr*/ @@ -59,54 +70,67 @@ class AccountsToPostgres { print("✅ Account succesfully created"); } - static Future selectHashById(String id) async { + static Future selectHashByMail(String mail) async { List> results = await connection.query( - "SELECT hash FROM \"Account\" WHERE id=@identifiant", - substitutionValues: {"identifiant": id}); + "SELECT hash FROM \"Account\" WHERE mail=@mail", + substitutionValues: {"mail": mail}); - closeConnection(); return results[0][0]; } - static Future updatePass( - String identifiant, String hash, String salt) async { - if (selectHashById(identifiant) == null) { + static Future checkMailAlreadyExist(String mail) async { + List> results = await connection.query( + "SELECT id FROM \"Account\" WHERE mail=@mail", + substitutionValues: {"mail": mail}); + print(results[0][0]); + + return; + } + + static Future updatePass(String mail, String hash, String salt) async { + if (selectHashByMail(mail) == null) { return; } else { await connection.query( - "UPDATE \"Account\" SET hash=@h, salt=@s WHERE id=@identifiant", - substitutionValues: { - "identifiant": identifiant, - "h": hash, - "s": salt - }); + "UPDATE \"Account\" SET hash=@hash, salt=@salt WHERE mail=@mail", + substitutionValues: {"mail": mail, "hash": hash, "salt": salt}); } } - static Future updateFilePass( - String identifiant, File passwordFile) async { + static Future updateFilePass(String mail, File passwordFile) async { List passwordBlob = utf8.encode(await passwordFile.readAsString(encoding: utf8)); - if (selectHashById(identifiant) == null) { + if (selectHashByMail(mail) == null) { return; } else { await connection.query( "UPDATE \"Account\" SET passwords=@p WHERE id=@identifiant", - substitutionValues: {"identifiant": identifiant, "p": passwordBlob}); + substitutionValues: {"identifiant": mail, "p": passwordBlob}); } } - static Future updateTwoFa(String identifiant, List tfa) async { + static Future updateTwoFa(String mail, List tfa) async { List twoFaStr = List.empty(growable: true); - if (selectHashById(identifiant) == null) { + if (selectHashByMail(mail) == null) { return; } else { await connection.query( "UPDATE \"Account\" SET twofa=@tfa WHERE id=@identifiant", - substitutionValues: {"identifiant": identifiant, "tfa": tfa}); + substitutionValues: {"identifiant": mail, "tfa": tfa}); + } + } + + static Future updateMail(String mail, String newMail) async { + if (selectHashByMail(mail) == null) { + return; + } else { + await connection.query( + "UPDATE \"Account\" SET mail=@newMail WHERE mail=@mail", + substitutionValues: {"newMail": newMail, "mail": mail}); } + print("✅ Mail succesfully updated"); } static Future deleteById(String id) async { diff --git a/pubspec.lock b/pubspec.lock index b687f02..6983a86 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -163,12 +163,12 @@ packages: source: hosted version: "1.8.0" mime: - dependency: transitive + dependency: "direct main" description: name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.3" node_preamble: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a7cafa0..2bb3c0f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,6 +8,7 @@ environment: dependencies: args: ^2.0.0 + mime: ^1.0.3 path: ^1.8.2 postgres: ^2.5.2 shelf: ^1.1.0