Skip to content

Commit

Permalink
Extend validateDetails to handle Hello and Welcome details
Browse files Browse the repository at this point in the history
  • Loading branch information
muzzammilshahid committed May 22, 2024
1 parent 41351c9 commit 744e0a3
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 105 deletions.
25 changes: 7 additions & 18 deletions lib/src/messages/hello.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,13 @@ class Hello implements Message {
static Hello parse(final List<dynamic> message) {
var fields = validateMessage(message, id, text, _validationSpec);

Map<String, dynamic> roles = validateRolesOrRaise(fields.details!["roles"], text);

String authid = "";
if (fields.details!["authid"] != null) {
authid = validateStringOrRaise(fields.details!["authid"], text, "authid");
}

List<dynamic> authMethods = [];
if (fields.details!["authmethods"] != null) {
authMethods = validateListOrRaise(fields.details!["authmethods"], text, "authmethods");
}

Map<String, dynamic>? authExtra;
if (fields.details!["authextra"] != null) {
authExtra = validateMapOrRaise(fields.details!["authextra"], text, "authextra");
}

return Hello(fields.realm!, roles, authid, authMethods, authExtra: authExtra);
return Hello(
fields.realm!,
fields.details!["roles"],
fields.details!["authid"],
fields.details!["authmethods"],
authExtra: fields.details!["authextra"],
);
}

@override
Expand Down
89 changes: 48 additions & 41 deletions lib/src/messages/util.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "package:wampproto/messages.dart";
import "package:wampproto/src/exception.dart";
import "package:wampproto/src/messages/validation_spec.dart";

Expand Down Expand Up @@ -71,58 +72,22 @@ void sanityCheck(List<dynamic> wampMessage, int minLength, int maxLength, int ex
}
}

String validateStringOrRaise(Object? string, String errorMsg, String field) {
if (string == null) {
throw ProtocolError("$field cannot be null for $errorMsg");
}

if (string is! String) {
throw ProtocolError("$field must be of type string for $errorMsg");
}

return string;
}

Map<String, dynamic> validateMapOrRaise(Object? map, String errorMsg, String field) {
if (map == null) {
throw ProtocolError("$field cannot be null for $errorMsg");
}

if (map is! Map) {
throw ProtocolError("$field must be of type map for $errorMsg");
}

return map.cast();
}

List<dynamic> validateListOrRaise(Object? list, String errorMsg, String field) {
if (list == null) {
throw ProtocolError("$field cannot be null for $errorMsg");
}

if (list is! List<dynamic>) {
throw ProtocolError("$field must be of type list for $errorMsg");
}

return list;
}

Map<String, dynamic> validateRolesOrRaise(Object? roles, String errorMsg) {
String? validateRoles(Object? roles, String message) {
if (roles == null) {
throw ProtocolError("roles cannot be null for $errorMsg");
return "roles cannot be null for $message";
}

if (roles is! Map) {
throw ProtocolError("roles must be of type map for $errorMsg but was ${roles.runtimeType}");
return "roles must be of type map for $message but was ${roles.runtimeType} for $message";
}

for (final role in roles.keys) {
if (!allowedRoles.contains(role)) {
throw ProtocolError("invalid role '$role' in 'roles' details for $errorMsg");
return "invalid role '$role' in 'roles' details for $message";
}
}

return roles.cast();
return null;
}

String? validateInt(Object value, int index, String message) {
Expand Down Expand Up @@ -264,6 +229,48 @@ String? validateDetails(List<dynamic> msg, int index, Fields fields, String mess
return error;
}
fields.details = (msg[index] as Map).cast();

if (message == Hello.text || message == Welcome.text) {
if (message == Hello.text) {
fields.details!["authmethods"] ??= [];
var errAuthMethods = validateList(fields.details!["authmethods"], 1, "authmethods");
if (errAuthMethods != null) {
return "authmethods must be of type list in details for $message";
}

fields.details!["authid"] ??= "";
} else {
var errAuthRole = validateString(fields.details!["authrole"], 1, message);
if (errAuthRole != null) {
return "authrole must be of type string in details for $message";
}

var errAuthMethod = validateString(fields.details!["authmethod"], 1, message);
if (errAuthMethod != null) {
return "authmethod must be of type string in details for $message";
}
}

var err = validateRoles(fields.details!["roles"], message);
if (err != null) {
return err;
}
fields.details!["roles"] = (fields.details!["roles"] as Map).cast<String, dynamic>();

var errAuthID = validateString(fields.details!["authid"], 1, "authid");
if (errAuthID != null) {
return "authid must be of type string in details for $message";
}

if (fields.details!["authextra"] != null) {
var err = validateMap(fields.details!["authextra"], 1, "authextra");
if (err != null) {
return "authextra must be of type Map in details for $message";
}
fields.details!["authextra"] = (fields.details!["authextra"] as Map).cast<String, dynamic>();
}
}

return null;
}

Expand Down
22 changes: 8 additions & 14 deletions lib/src/messages/welcome.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,14 @@ class Welcome implements Message {
static Welcome parse(final List<dynamic> message) {
var fields = validateMessage(message, id, text, _validationSpec);

Map<String, dynamic> roles = validateRolesOrRaise(fields.details!["roles"], text);

String authid = validateStringOrRaise(fields.details!["authid"], text, "authid");

String authRole = validateStringOrRaise(fields.details!["authrole"], text, "authrole");

String authMethod = validateStringOrRaise(fields.details!["authmethod"], text, "authmethod");

Map<String, dynamic>? authExtra;
if (fields.details!["authextra"] != null) {
authExtra = validateMapOrRaise(fields.details!["authextra"], text, "authextra");
}

return Welcome(fields.sessionID!, roles, authid, authRole, authMethod, authExtra: authExtra);
return Welcome(
fields.sessionID!,
fields.details!["roles"],
fields.details!["authid"],
fields.details!["authrole"],
fields.details!["authmethod"],
authExtra: fields.details!["authextra"],
);
}

@override
Expand Down
129 changes: 97 additions & 32 deletions test/messages/util_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import "package:test/test.dart";
import "package:wampproto/messages.dart";
import "package:wampproto/src/messages/util.dart";
import "package:wampproto/src/messages/validation_spec.dart";

Expand All @@ -16,38 +17,6 @@ void main() {
expect(() => sanityCheck([2, 2, 3], 2, 4, 1, "TestMessage"), throwsException);
});

test("validateStringOrRaise", () {
// valid string
expect(validateStringOrRaise("test", "errorMsg", "field"), "test");

// invalid string
expect(() => validateStringOrRaise(123, "errorMsg", "field"), throwsException);
});

test("validateMapOrRaise", () {
// valid map
expect(validateMapOrRaise({"key": "value"}, "errorMsg", "field"), {"key": "value"});

// invalid map
expect(() => validateMapOrRaise(123, "errorMsg", "field"), throwsException);
});

test("validateListOrRaise", () {
// valid list
expect(validateListOrRaise([1, 2, 3], "errorMsg", "field"), [1, 2, 3]);

// invalid list
expect(() => validateListOrRaise(123, "errorMsg", "field"), throwsException);
});

test("validateRolesOrRaise", () {
// valid roles
expect(validateRolesOrRaise({"caller": {}, "callee": {}}, "errorMsg"), {"caller": {}, "callee": {}});

// invalid roles
expect(() => validateRolesOrRaise({"invalidRole": {}}, "errorMsg"), throwsException);
});

test("validateInt", () {
// valid int
expect(validateInt(123, 0, "message"), isNull);
Expand Down Expand Up @@ -129,6 +98,28 @@ void main() {
expect(validateList("string", 0, "message"), isNotNull);
});

test("validateRoles", () {
// valid roles
var result = validateRoles({"callee": {}, "caller": {}}, "TestMessage");
expect(result, isNull);

// empty roles
result = validateRoles({}, "TestMessage");
expect(result, isNull);

// null roles
result = validateRoles(null, "TestMessage");
expect(result, "roles cannot be null for TestMessage");

// invalid roles type
result = validateRoles("not_a_map", "TestMessage");
expect(result, "roles must be of type map for TestMessage but was String for TestMessage");

// invalid roles
result = validateRoles({"invalid_role": {}}, "TestMessage");
expect(result, "invalid role 'invalid_role' in 'roles' details for TestMessage");
});

test("validateArgs", () {
Fields fields = Fields();

Expand Down Expand Up @@ -220,6 +211,80 @@ void main() {

// invalid details
expect(validateDetails(["string"], 0, fields, "message"), isNotNull);

// valid Hello message
var validHelloDetails = [
{
"authid": "user123",
"authmethods": ["password"],
"roles": {},
"authextra": {},
},
];
expect(validateDetails(validHelloDetails, 0, fields, Hello.text), isNull);

// valid Welcome details
var validWelcomeDetails = [
{"authid": "user123", "authrole": "admin", "authmethod": "password", "roles": {}, "authextra": {}},
];
expect(validateDetails(validWelcomeDetails, 0, fields, Welcome.text), isNull);

// authmethods is not a list for Hello message
var invalidAuthMethods = [
{"authid": "user123", "authmethods": "not_a_list", "roles": {}, "authextra": {}},
];
var invalidAuthMethodsResult = validateDetails(invalidAuthMethods, 0, fields, Hello.text);
expect(invalidAuthMethodsResult, "authmethods must be of type list in details for ${Hello.text}");

// authrole is not a string for Welcome message
var invalidAuthRole = [
{"authid": "user123", "authrole": 123, "authmethod": "password", "roles": {}, "authextra": {}},
];
var invalidAuthRoleResult = validateDetails(invalidAuthRole, 0, fields, Welcome.text);
expect(invalidAuthRoleResult, "authrole must be of type string in details for ${Welcome.text}");

// authmethod is not a string for Welcome message
var invalidAuthMethod = [
{"authid": "user123", "authrole": "admin", "authmethod": 123, "roles": {}, "authextra": {}},
];
var invalidAuthMethodResult = validateDetails(invalidAuthMethod, 0, fields, Welcome.text);
expect(invalidAuthMethodResult, "authmethod must be of type string in details for ${Welcome.text}");

// invalid roles
var invalidRoles = [
{
"authid": "user123",
"authmethods": ["password"],
"roles": "not_a_map",
"authextra": {},
},
];
var invalidRolesResult = validateDetails(invalidRoles, 0, fields, Hello.text);
expect(invalidRolesResult, "roles must be of type map for HELLO but was String for ${Hello.text}");

// invalid authextra
var invalidAuthExtra = [
{
"authid": "user123",
"authmethods": ["password"],
"roles": {},
"authextra": "not_a_map",
},
];
var invalidAuthExtraResult = validateDetails(invalidAuthExtra, 0, fields, Hello.text);
expect(invalidAuthExtraResult, "authextra must be of type Map in details for ${Hello.text}");

// invalid authid
var invalidAuthID = [
{
"authid": 123,
"authmethods": ["password"],
"roles": {},
"authextra": {},
},
];
var resultInvalidAuthID = validateDetails(invalidAuthID, 0, fields, Hello.text);
expect(resultInvalidAuthID, "authid must be of type string in details for ${Hello.text}");
});

test("validateReason", () {
Expand Down

0 comments on commit 744e0a3

Please sign in to comment.