[FF-235] delete identify: challenge, identity class (#410)

This commit is contained in:
Boris 2021-11-26 10:34:34 +03:00 committed by GitHub
parent 4d112ad5b3
commit f6155acb04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 279 additions and 1628 deletions

View File

@ -161,40 +161,37 @@ configure_processing_apps(Options) ->
ok = create_crunch_identity(
dummy_payment_inst_identity_id(Options),
dummy_provider_identity_id(Options),
<<"quote-owner">>
<<"good-two">>
).
create_crunch_identity(PayInstIID, ProviderIID, ProviderID) ->
PartyID = create_party(),
PayInstIID = create_identity(PayInstIID, <<"ChurchPI">>, PartyID, ProviderID, <<"church">>),
ProviderIID = create_identity(ProviderIID, <<"ChurchPR">>, PartyID, ProviderID, <<"church">>),
PayInstIID = create_identity(PayInstIID, <<"ChurchPI">>, PartyID, ProviderID),
ProviderIID = create_identity(ProviderIID, <<"ChurchPR">>, PartyID, ProviderID),
ok.
create_company_account() ->
PartyID = create_party(),
IdentityID = create_company_identity(PartyID, <<"good-one">>),
IdentityID = create_identity(PartyID, <<"good-one">>),
{ok, Currency} = ff_currency:get(<<"RUB">>),
{ok, IdentityMachine} = ff_identity_machine:get(IdentityID),
Identity = ff_identity_machine:identity(IdentityMachine),
{ok, [{created, Account}]} = ff_account:create(PartyID, Identity, Currency),
Account.
create_company_identity(PartyID, ProviderID) ->
create_identity(PartyID, ProviderID, <<"church">>).
create_party() ->
ID = genlib:bsuuid(),
_ = ff_party:create(ID),
ID.
create_identity(PartyID, ProviderID, ClassID) ->
create_identity(PartyID, ProviderID) ->
ID = genlib:unique(),
Name = <<"Test Identity">>,
create_identity(ID, Name, PartyID, ProviderID, ClassID).
create_identity(ID, Name, PartyID, ProviderID).
create_identity(ID, Name, PartyID, ProviderID, ClassID) ->
create_identity(ID, Name, PartyID, ProviderID) ->
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => PartyID, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => PartyID, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.
@ -211,125 +208,17 @@ do_set_env([Key | Path], Value, Env) ->
Env#{Key => do_set_env(Path, Value, SubEnv)}.
%% Default options
identity_provider_config(Options) ->
Default = #{
<<"good-one">> => #{
payment_institution_id => 1,
routes => [<<"mocketbank">>],
identity_classes => #{
<<"person">> => #{
name => <<"Well, a person">>,
contract_template_id => 1,
initial_level => <<"peasant">>,
levels => #{
<<"peasant">> => #{
name => <<"Well, a peasant">>,
contractor_level => none
},
<<"nobleman">> => #{
name => <<"Well, a nobleman">>,
contractor_level => partial
}
},
challenges => #{
<<"sword-initiation">> => #{
name => <<"Initiation by sword">>,
base => <<"peasant">>,
target => <<"nobleman">>
}
}
},
<<"church">> => #{
name => <<"Well, a Сhurch">>,
contract_template_id => 2,
initial_level => <<"mainline">>,
levels => #{
<<"mainline">> => #{
name => <<"Well, a mainline Сhurch">>,
contractor_level => full
}
}
}
}
contract_template_id => 1,
contractor_level => full
},
<<"good-two">> => #{
payment_institution_id => 1,
routes => [<<"mocketbank">>],
identity_classes => #{
<<"person">> => #{
name => <<"Well, a person">>,
contract_template_id => 1,
initial_level => <<"peasant">>,
levels => #{
<<"peasant">> => #{
name => <<"Well, a peasant">>,
contractor_level => none
},
<<"nobleman">> => #{
name => <<"Well, a nobleman">>,
contractor_level => partial
}
},
challenges => #{
<<"sword-initiation">> => #{
name => <<"Initiation by sword">>,
base => <<"peasant">>,
target => <<"nobleman">>
}
}
},
<<"church">> => #{
name => <<"Well, a Сhurch">>,
contract_template_id => 2,
initial_level => <<"mainline">>,
levels => #{
<<"mainline">> => #{
name => <<"Well, a mainline Сhurch">>,
contractor_level => full
}
}
}
}
},
<<"quote-owner">> => #{
payment_institution_id => 2,
routes => [<<"quotebank">>],
identity_classes => #{
<<"person">> => #{
name => <<"Well, a person">>,
contract_template_id => 1,
initial_level => <<"peasant">>,
levels => #{
<<"peasant">> => #{
name => <<"Well, a peasant">>,
contractor_level => none
},
<<"nobleman">> => #{
name => <<"Well, a nobleman">>,
contractor_level => partial
}
},
challenges => #{
<<"sword-initiation">> => #{
name => <<"Initiation by sword">>,
base => <<"peasant">>,
target => <<"nobleman">>
}
}
},
<<"church">> => #{
name => <<"Well, a Сhurch">>,
contract_template_id => 2,
initial_level => <<"mainline">>,
levels => #{
<<"mainline">> => #{
name => <<"Well, a mainline Сhurch">>,
contractor_level => full
}
}
}
}
contract_template_id => 1,
contractor_level => full
}
},
maps:get(identity_provider_config, Options, Default).

View File

@ -5,10 +5,8 @@
-include_lib("fistful_proto/include/ff_proto_identity_thrift.hrl").
-export([unmarshal_identity_params/1]).
-export([unmarshal_challenge_params/1]).
-export([marshal_identity_event/1]).
-export([marshal_challenge_state/1]).
-export([marshal_identity_state/2]).
-export([marshal/2]).
@ -21,7 +19,6 @@ unmarshal_identity_params(#idnt_IdentityParams{
name = Name,
party = PartyID,
provider = ProviderID,
cls = ClassID,
external_id = ExternalID,
metadata = Metadata
}) ->
@ -30,24 +27,10 @@ unmarshal_identity_params(#idnt_IdentityParams{
name => unmarshal(string, Name),
party => unmarshal(id, PartyID),
provider => unmarshal(id, ProviderID),
class => unmarshal(id, ClassID),
external_id => maybe_unmarshal(id, ExternalID),
metadata => maybe_unmarshal(ctx, Metadata)
}).
-spec unmarshal_challenge_params(ff_proto_identity_thrift:'ChallengeParams'()) ->
ff_identity_machine:challenge_params().
unmarshal_challenge_params(#idnt_ChallengeParams{
id = ID,
cls = ClassID,
proofs = Proofs
}) ->
genlib_map:compact(#{
id => unmarshal(id, ID),
class => unmarshal(id, ClassID),
proofs => unmarshal({list, challenge_proofs}, Proofs)
}).
-spec marshal_identity_event({integer(), ff_machine:timestamped_event(ff_identity:event())}) ->
ff_proto_identity_thrift:'Event'().
marshal_identity_event({ID, {ev, Timestamp, Ev}}) ->
@ -57,38 +40,19 @@ marshal_identity_event({ID, {ev, Timestamp, Ev}}) ->
change = marshal(change, Ev)
}.
-spec marshal_challenge_state(ff_identity_challenge:challenge_state()) -> ff_proto_identity_thrift:'ChallengeState'().
marshal_challenge_state(ChallengeState) ->
Proofs = ff_identity_challenge:proofs(ChallengeState),
Status = ff_identity_challenge:status(ChallengeState),
#idnt_ChallengeState{
id = ff_identity_challenge:id(ChallengeState),
cls = ff_identity_challenge:class(ChallengeState),
proofs = marshal({list, challenge_proofs}, Proofs),
status = marshal(challenge_payload_status_changed, Status)
}.
-spec marshal_identity_state(ff_identity:identity_state(), ff_entity_context:context()) ->
ff_proto_identity_thrift:'IdentityState'().
marshal_identity_state(IdentityState, Context) ->
EffectiveChallengeID =
case ff_identity:effective_challenge(IdentityState) of
{ok, ID} -> maybe_marshal(id, ID);
{error, notfound} -> undefined
end,
#idnt_IdentityState{
id = maybe_marshal(id, ff_identity:id(IdentityState)),
name = marshal(string, ff_identity:name(IdentityState)),
party_id = marshal(id, ff_identity:party(IdentityState)),
provider_id = marshal(id, ff_identity:provider(IdentityState)),
class_id = marshal(id, ff_identity:class(IdentityState)),
contract_id = maybe_marshal(id, ff_identity:contract(IdentityState)),
level_id = maybe_marshal(id, ff_identity:level(IdentityState)),
blocking = maybe_marshal(blocking, ff_identity:blocking(IdentityState)),
created_at = maybe_marshal(created_at, ff_identity:created_at(IdentityState)),
external_id = maybe_marshal(id, ff_identity:external_id(IdentityState)),
metadata = maybe_marshal(ctx, ff_identity:metadata(IdentityState)),
effective_challenge_id = EffectiveChallengeID,
context = maybe_marshal(ctx, Context)
}.
@ -102,81 +66,17 @@ marshal(timestamped_change, {ev, Timestamp, Change}) ->
};
marshal(change, {created, Identity}) ->
{created, marshal(identity, Identity)};
marshal(change, {level_changed, LevelID}) ->
{level_changed, marshal(id, LevelID)};
marshal(change, {{challenge, ChallengeID}, ChallengeChange}) ->
{identity_challenge,
marshal(challenge_change, #{
id => ChallengeID,
payload => ChallengeChange
})};
marshal(change, {effective_challenge_changed, ChallengeID}) ->
{effective_challenge_changed, marshal(id, ChallengeID)};
marshal(identity, Identity) ->
#idnt_Identity{
id = maybe_marshal(id, ff_identity:id(Identity)),
name = maybe_marshal(string, ff_identity:name(Identity)),
party = marshal(id, ff_identity:party(Identity)),
provider = marshal(id, ff_identity:provider(Identity)),
cls = marshal(id, ff_identity:class(Identity)),
contract = maybe_marshal(id, ff_identity:contract(Identity)),
created_at = maybe_marshal(created_at, ff_identity:created_at(Identity)),
external_id = maybe_marshal(id, ff_identity:external_id(Identity)),
metadata = maybe_marshal(ctx, ff_identity:metadata(Identity))
};
marshal(challenge_change, #{
id := ID,
payload := Payload
}) ->
#idnt_ChallengeChange{
id = marshal(id, ID),
payload = marshal(challenge_payload, Payload)
};
marshal(challenge_payload, {created, Challenge}) ->
{created, marshal(challenge_payload_created, Challenge)};
marshal(challenge_payload, {status_changed, ChallengeStatus}) ->
{status_changed, marshal(challenge_payload_status_changed, ChallengeStatus)};
marshal(
challenge_payload_created,
Challenge = #{
id := ID
}
) ->
Proofs = maps:get(proofs, Challenge, []),
#idnt_Challenge{
id = marshal(id, ID),
cls = marshal(id, maps:get(challenge_class, Challenge)),
provider_id = marshal(id, maps:get(provider, Challenge)),
class_id = marshal(id, maps:get(identity_class, Challenge)),
proofs = marshal({list, challenge_proofs}, Proofs),
claim_id = marshal(id, maps:get(claim_id, Challenge)),
claimant = marshal(id, maps:get(claimant, Challenge)),
master_id = marshal(id, maps:get(master_id, Challenge))
};
marshal(challenge_proofs, {Type, Token}) ->
#idnt_ChallengeProof{
type = Type,
token = Token
};
marshal(challenge_payload_status_changed, pending) ->
{pending, #idnt_ChallengePending{}};
marshal(challenge_payload_status_changed, cancelled) ->
{cancelled, #idnt_ChallengeCancelled{}};
marshal(
challenge_payload_status_changed,
{completed,
Status = #{
resolution := Resolution
}}
) ->
ValidUntil = maps:get(valid_until, Status, undefined),
NewStatus = #idnt_ChallengeCompleted{
resolution = marshal(resolution, Resolution),
valid_until = marshal(timestamp, ValidUntil)
},
{completed, NewStatus};
marshal(challenge_payload_status_changed, {failed, _Status}) ->
{failed, #idnt_ChallengeFailed{}};
marshal(resolution, approved) ->
approved;
marshal(resolution, denied) ->
@ -203,6 +103,7 @@ unmarshal(repair_scenario, {add_events, #idnt_AddEventsRepair{events = Events, a
})};
unmarshal(change, {created, Identity}) ->
{created, unmarshal(identity, Identity)};
% We have to support this unmarshal cause mg contain identety's events with challenge
unmarshal(change, {level_changed, LevelID}) ->
{level_changed, unmarshal(id, LevelID)};
unmarshal(change, {identity_challenge, #idnt_ChallengeChange{id = ID, payload = Payload}}) ->
@ -214,7 +115,6 @@ unmarshal(identity, #idnt_Identity{
name = Name,
party = PartyID,
provider = ProviderID,
cls = ClassID,
contract = ContractID,
external_id = ExternalID,
created_at = CreatedAt,
@ -225,7 +125,6 @@ unmarshal(identity, #idnt_Identity{
name => unmarshal(string, Name),
party => unmarshal(id, PartyID),
provider => unmarshal(id, ProviderID),
class => unmarshal(id, ClassID),
contract => unmarshal(id, ContractID),
external_id => maybe_unmarshal(id, ExternalID),
created_at => maybe_unmarshal(created_at, CreatedAt),
@ -326,7 +225,6 @@ identity_test() ->
name => genlib:unique(),
party => genlib:unique(),
provider => genlib:unique(),
class => genlib:unique(),
contract => genlib:unique(),
external_id => genlib:unique(),
version => 2
@ -334,19 +232,4 @@ identity_test() ->
IdentityOut = unmarshal(identity, marshal(identity, IdentityIn)),
?assertEqual(IdentityOut, IdentityIn).
-spec challenge_test() -> _.
challenge_test() ->
ChallengeIn = #{
id => genlib:unique(),
proofs => [{rus_retiree_insurance_cert, <<"Bananazzzz">>}],
challenge_class => <<"challenge_class">>,
claim_id => <<"claim_id">>,
provider => <<"provider">>,
identity_class => <<"identity_class">>,
master_id => <<"master_id">>,
claimant => <<"claimant">>
},
ChallengeOut = unmarshal(challenge_payload_created, marshal(challenge_payload_created, ChallengeIn)),
?assertEqual(ChallengeIn, ChallengeOut).
-endif.

View File

@ -34,8 +34,6 @@ handle_function_('Create', {IdentityParams, Context}, Opts) ->
woody_error:raise(business, #fistful_ProviderNotFound{});
{error, {party, notfound}} ->
woody_error:raise(business, #fistful_PartyNotFound{});
{error, {identity_class, notfound}} ->
woody_error:raise(business, #fistful_IdentityClassNotFound{});
{error, {inaccessible, _}} ->
woody_error:raise(business, #fistful_PartyInaccessible{});
{error, exists} ->
@ -62,42 +60,6 @@ handle_function_('GetContext', {ID}, _Opts) ->
{error, notfound} ->
woody_error:raise(business, #fistful_IdentityNotFound{})
end;
handle_function_('StartChallenge', {IdentityID, Params}, _Opts) ->
%% Не используем ExternalID тк идемпотентность реал-на через challengeID
ChallengeParams = ff_identity_codec:unmarshal_challenge_params(Params),
case ff_identity_machine:start_challenge(IdentityID, ChallengeParams) of
ok ->
ChallengeID = maps:get(id, ChallengeParams),
{ok, Machine} = ff_identity_machine:get(IdentityID),
Identity = ff_identity_machine:identity(Machine),
{ok, Challenge} = ff_identity:challenge(ChallengeID, Identity),
{ok, ff_identity_codec:marshal_challenge_state(Challenge)};
{error, notfound} ->
woody_error:raise(business, #fistful_IdentityNotFound{});
{error, {challenge, {pending, _}}} ->
woody_error:raise(business, #fistful_ChallengePending{});
{error, {challenge, {challenge_class, notfound}}} ->
woody_error:raise(business, #fistful_ChallengeClassNotFound{});
{error, {challenge, {proof, notfound}}} ->
woody_error:raise(business, #fistful_ProofNotFound{});
{error, {challenge, {proof, insufficient}}} ->
woody_error:raise(business, #fistful_ProofInsufficient{});
{error, {challenge, {level, _}}} ->
woody_error:raise(business, #fistful_ChallengeLevelIncorrect{});
{error, {challenge, conflict}} ->
woody_error:raise(business, #fistful_ChallengeConflict{});
{error, Error} ->
woody_error:raise(system, {internal, result_unexpected, woody_error:format_details(Error)})
end;
handle_function_('GetChallenges', {ID}, _Opts) ->
case ff_identity_machine:get(ID) of
{ok, Machine} ->
Identity = ff_identity_machine:identity(Machine),
Challenges = ff_identity:challenges(Identity),
{ok, [ff_identity_codec:marshal_challenge_state(C) || C <- maps:values(Challenges)]};
{error, notfound} ->
woody_error:raise(business, #fistful_IdentityNotFound{})
end;
handle_function_('GetEvents', {IdentityID, EventRange}, _Opts) ->
case ff_identity_machine:events(IdentityID, ff_codec:unmarshal(event_range, EventRange)) of
{ok, EventList} ->

View File

@ -200,7 +200,6 @@ unmarshal(Type, Value) ->
-spec created_v0_decoding_test() -> _.
created_v0_decoding_test() ->
Identity = #{
class => <<"class">>,
contract => <<"ContractID">>,
created_at => 1592576943762,
id => <<"ID">>,
@ -390,9 +389,7 @@ challenge_created_v0_decoding_test() ->
]},
DecodedLegacy = unmarshal({event, undefined}, LegacyEvent),
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
?assertEqual(Event, Decoded).
?assertEqual(Event, DecodedLegacy).
-spec challenge_status_changed_v0_decoding_test() -> _.
challenge_status_changed_v0_decoding_test() ->
@ -430,14 +427,11 @@ challenge_status_changed_v0_decoding_test() ->
]},
DecodedLegacy = unmarshal({event, undefined}, LegacyEvent),
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
?assertEqual(Event, Decoded).
?assertEqual(Event, DecodedLegacy).
-spec created_v1_decoding_test() -> _.
created_v1_decoding_test() ->
Identity = #{
class => <<"class">>,
contract => <<"ContractID">>,
created_at => 1592576943762,
id => <<"ID">>,
@ -458,9 +452,7 @@ created_v1_decoding_test() ->
>>)},
C = make_legacy_context(#{ctx => #{<<"com.rbkmoney.wapi">> => #{<<"name">> => <<"Name">>}}}),
{DecodedLegacy, _} = unmarshal({event, 1}, LegacyEvent, C),
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
{Decoded, _} = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary, C),
?assertEqual(Event, Decoded).
?assertEqual(Event, DecodedLegacy).
-spec level_changed_v1_decoding_test() -> _.
level_changed_v1_decoding_test() ->
@ -472,9 +464,7 @@ level_changed_v1_decoding_test() ->
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgsAAgAAAA1sZXZlbF9jaGFuZ2VkAAA="
>>)},
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
?assertEqual(Event, Decoded).
?assertEqual(Event, DecodedLegacy).
-spec effective_challenge_changed_v1_decoding_test() -> _.
effective_challenge_changed_v1_decoding_test() ->
@ -515,9 +505,7 @@ challenge_created_v1_decoding_test() ->
"NsYWltX2lkCwAIAAAACW1hc3Rlcl9pZAsACQAAAAhjbGFpbWFudAAAAAAA"
>>)},
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
?assertEqual(Event, Decoded).
?assertEqual(Event, DecodedLegacy).
-spec challenge_status_changed_v1_decoding_test() -> _.
challenge_status_changed_v1_decoding_test() ->
@ -529,14 +517,11 @@ challenge_status_changed_v1_decoding_test() ->
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwsAAQAAAAtjaGFsbGVuZ2VJRAwAAgwAAgwAAQAAAAAAAA=="
>>)},
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
?assertEqual(Event, Decoded).
?assertEqual(Event, DecodedLegacy).
-spec created_v2_decoding_test() -> _.
created_v2_decoding_test() ->
Identity = #{
class => <<"class">>,
contract => <<"ContractID">>,
created_at => 1592576943762,
id => <<"ID">>,
@ -557,9 +542,7 @@ created_v2_decoding_test() ->
"YWwAAAAA"
>>)},
DecodedLegacy = unmarshal({event, 2}, LegacyEvent),
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
?assertEqual(Event, Decoded).
?assertEqual(Event, DecodedLegacy).
-spec level_changed_v2_decoding_test() -> _.
level_changed_v2_decoding_test() ->
@ -571,9 +554,7 @@ level_changed_v2_decoding_test() ->
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgsAAgAAAA1sZXZlbF9jaGFuZ2VkAAA="
>>)},
DecodedLegacy = unmarshal({event, 2}, LegacyEvent),
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
?assertEqual(Event, Decoded).
?assertEqual(Event, DecodedLegacy).
-spec effective_challenge_changed_v2_decoding_test() -> _.
effective_challenge_changed_v2_decoding_test() ->
@ -585,9 +566,7 @@ effective_challenge_changed_v2_decoding_test() ->
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgsABAAAABtlZmZlY3RpdmVfY2hhbGxlbmdlX2NoYW5nZWQAAA=="
>>)},
DecodedLegacy = unmarshal({event, 2}, LegacyEvent),
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
?assertEqual(Event, Decoded).
?assertEqual(Event, DecodedLegacy).
-spec challenge_created_v2_decoding_test() -> _.
challenge_created_v2_decoding_test() ->
@ -614,9 +593,7 @@ challenge_created_v2_decoding_test() ->
"NsYWltX2lkCwAIAAAACW1hc3Rlcl9pZAsACQAAAAhjbGFpbWFudAAAAAAA"
>>)},
DecodedLegacy = unmarshal({event, 2}, LegacyEvent),
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
?assertEqual(Event, Decoded).
?assertEqual(Event, DecodedLegacy).
-spec challenge_status_changed_v2_decoding_test() -> _.
challenge_status_changed_v2_decoding_test() ->
@ -628,8 +605,6 @@ challenge_status_changed_v2_decoding_test() ->
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwsAAQAAAAtjaGFsbGVuZ2VJRAwAAgwAAgwAAQAAAAAAAA=="
>>)},
DecodedLegacy = unmarshal({event, 2}, LegacyEvent),
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
?assertEqual(Event, Decoded).
?assertEqual(Event, DecodedLegacy).
-endif.

View File

@ -46,12 +46,10 @@ marshal_provider(Provider) ->
ID = ff_provider:id(Provider),
Name = ff_provider:name(Provider),
Residences = ff_provider:residences(Provider),
IdentityClasses = ff_provider:identity_classes(Provider),
#provider_Provider{
id = ID,
name = Name,
residences = marshal_residences(ordsets:to_list(Residences)),
identity_classes = marshal_identity_classes(IdentityClasses)
residences = marshal_residences(ordsets:to_list(Residences))
}.
marshal_residences(List) ->
@ -59,15 +57,3 @@ marshal_residences(List) ->
marshal_residence(Residence) ->
genlib_string:to_upper(genlib:to_binary(Residence)).
-spec marshal_identity_classes(ff_provider:identity_classes()) ->
#{ff_proto_provider_thrift:'IdentityClassID'() => ff_proto_provider_thrift:'IdentityClass'()}.
marshal_identity_classes(Map) ->
maps:map(fun(_ClassID, Class) -> marshal_identity_class(Class) end, Map).
-spec marshal_identity_class(ff_identity_class:class()) -> ff_proto_provider_thrift:'IdentityClass'().
marshal_identity_class(Class) ->
#provider_IdentityClass{
id = ff_identity_class:id(Class),
name = ff_identity_class:name(Class)
}.

View File

@ -560,7 +560,7 @@ call_deposit(Fun, Args) ->
prepare_standard_environment(Body, C) ->
#'Cash'{currency = #'CurrencyRef'{symbolic_code = Currency}} = Body,
Party = create_party(C),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
WalletID = create_wallet(IdentityID, <<"My wallet">>, <<"RUB">>, C),
ok = await_wallet_balance({0, Currency}, WalletID),
SourceID = create_source(IdentityID, C),
@ -687,19 +687,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -127,7 +127,7 @@ create_destination_ok(Resource, C) ->
DstName = <<"loSHara card">>,
ID = genlib:unique(),
ExternalId = genlib:unique(),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
Ctx = ff_entity_context_codec:marshal(#{<<"NS">> => #{}}),
Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}),
Params = #dst_DestinationParams{
@ -179,16 +179,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_identity(Party, <<"good-one">>, <<"person">>, C).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -94,30 +94,10 @@ get_identity_events_ok(C) ->
id => ID,
name => Name,
party => Party,
provider => <<"good-one">>,
class => <<"person">>
provider => <<"good-one">>
},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ICID = genlib:unique(),
D1 = ct_identdocstore:rus_retiree_insurance_cert(genlib:unique(), C),
D2 = ct_identdocstore:rus_domestic_passport(C),
ChallengeParams = #{
id => ICID,
class => <<"sword-initiation">>
},
ok = ff_identity_machine:start_challenge(
ID,
ChallengeParams#{proofs => [D1, D2]}
),
{completed, _} = ct_helper:await(
{completed, #{resolution => approved}},
fun() ->
{ok, S} = ff_identity_machine:get(ID),
{ok, IC} = ff_identity:challenge(ICID, ff_identity_machine:identity(S)),
ff_identity_challenge:status(IC)
end
),
{ok, RawEvents} = ff_identity_machine:events(ID, {undefined, 1000}),
{_Events, MaxID} = ct_eventsink:events(LastEvent, 1000, Sink),
@ -150,7 +130,7 @@ get_withdrawal_events_ok(C) ->
Sink = withdrawal_event_sink,
LastEvent = ct_eventsink:last_id(Sink),
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
WalID = create_wallet(IID, <<"HAHA NO2">>, <<"RUB">>, C),
SrcID = create_source(IID, C),
_DepID = process_deposit(SrcID, WalID),
@ -175,7 +155,7 @@ get_withdrawal_session_events_ok(C) ->
LastEvent = ct_eventsink:last_id(Sink),
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
WalID = create_wallet(IID, <<"HAHA NO2">>, <<"RUB">>, C),
SrcID = create_source(IID, C),
_DepID = process_deposit(SrcID, WalID),
@ -199,7 +179,7 @@ get_create_destination_events_ok(C) ->
LastEvent = ct_eventsink:last_id(Sink),
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
DestID = create_destination(IID, C),
{ok, RawEvents} = ff_destination_machine:events(DestID, {undefined, 1000}),
@ -212,7 +192,7 @@ get_create_source_events_ok(C) ->
LastEvent = ct_eventsink:last_id(Sink),
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
SrcID = create_source(IID, C),
{ok, RawEvents} = ff_source_machine:events(SrcID, {undefined, 1000}),
@ -225,7 +205,7 @@ get_create_deposit_events_ok(C) ->
LastEvent = ct_eventsink:last_id(Sink),
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
WalID = create_wallet(IID, <<"HAHA NO2">>, <<"RUB">>, C),
SrcID = create_source(IID, C),
DepID = process_deposit(SrcID, WalID),
@ -271,7 +251,7 @@ get_create_w2w_transfer_events_ok(C) ->
LastEvent = ct_eventsink:last_id(Sink),
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
WalFromID = create_wallet(IID, <<"HAHA NO1">>, <<"RUB">>, C),
WalToID = create_wallet(IID, <<"HAHA NO2">>, <<"RUB">>, C),
SrcID = create_source(IID, C),
@ -283,24 +263,21 @@ get_create_w2w_transfer_events_ok(C) ->
{_Events, MaxID} = ct_eventsink:events(LastEvent, 1000, Sink),
MaxID = LastEvent + length(RawEvents).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, <<"person">>, C).
create_party(_C) ->
ID = genlib:bsuuid(),
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_identity(Party, <<"good-one">>, <<"person">>, C).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.
@ -382,7 +359,8 @@ process_withdrawal(WalID, DestID) ->
{Events, _MaxID} = ct_eventsink:events(undefined, 1000, Sink),
search_event_commited(Events, WdrID)
end,
genlib_retry:linear(15, 1000)
% genlib_retry:linear(15, 1000)
genlib_retry:linear(5, 1000)
),
WdrID.

View File

@ -10,18 +10,10 @@
-export([end_per_testcase/2]).
-export([create_identity_ok/1]).
-export([run_challenge_ok/1]).
-export([get_challenge_event_ok/1]).
-export([get_event_unknown_identity_ok/1]).
-export([start_challenge_token_fail/1]).
-export([get_challenges_ok/1]).
-spec create_identity_ok(config()) -> test_return().
-spec run_challenge_ok(config()) -> test_return().
-spec get_challenge_event_ok(config()) -> test_return().
-spec get_event_unknown_identity_ok(config()) -> test_return().
-spec start_challenge_token_fail(config()) -> test_return().
-spec get_challenges_ok(config()) -> test_return().
%%
@ -33,12 +25,8 @@
-spec all() -> [test_case_name() | {group, group_name()}].
all() ->
[
get_challenges_ok,
create_identity_ok,
run_challenge_ok,
get_challenge_event_ok,
get_event_unknown_identity_ok,
start_challenge_token_fail
get_event_unknown_identity_ok
].
-spec init_per_suite(config()) -> config().
@ -76,10 +64,9 @@ create_identity_ok(_C) ->
EID = genlib:unique(),
Name = <<"Identity Name">>,
ProvID = <<"good-one">>,
ClassID = <<"person">>,
Ctx = #{<<"NS">> => #{<<"owner">> => PartyID}},
Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}),
Identity = create_identity(EID, Name, PartyID, ProvID, ClassID, Ctx, Metadata),
Identity = create_identity(EID, Name, PartyID, ProvID, Ctx, Metadata),
IID = Identity#idnt_IdentityState.id,
{ok, Identity_} = call_api('Get', {IID, #'EventRange'{}}),
@ -87,7 +74,6 @@ create_identity_ok(_C) ->
IID = Identity_#idnt_IdentityState.id,
Name = Identity_#idnt_IdentityState.name,
PartyID = Identity_#idnt_IdentityState.party_id,
ClassID = Identity_#idnt_IdentityState.class_id,
unblocked = Identity_#idnt_IdentityState.blocking,
Metadata = Identity_#idnt_IdentityState.metadata,
Ctx0 = Ctx#{
@ -96,143 +82,30 @@ create_identity_ok(_C) ->
Ctx0 = ff_entity_context_codec:unmarshal(Identity_#idnt_IdentityState.context),
ok.
run_challenge_ok(C) ->
Context = #{<<"NS">> => nil},
EID = genlib:unique(),
PartyID = create_party(),
ChallengeID = genlib:unique(),
Name = <<"Identity Name">>,
ProvID = <<"good-one">>,
ClassID = <<"person">>,
ChlClassID = <<"sword-initiation">>,
IdentityState = create_identity(EID, Name, PartyID, ProvID, ClassID, Context),
IID = IdentityState#idnt_IdentityState.id,
Params2 = gen_challenge_param(ChlClassID, ChallengeID, C),
{ok, Challenge} = call_api('StartChallenge', {IID, Params2}),
ChallengeID = Challenge#idnt_ChallengeState.id,
ChlClassID = Challenge#idnt_ChallengeState.cls,
Proofs = Params2#idnt_ChallengeParams.proofs,
Proofs = Challenge#idnt_ChallengeState.proofs,
true = {failed, #idnt_ChallengeFailed{}} =/= Challenge#idnt_ChallengeState.status.
get_challenge_event_ok(C) ->
Context = #{<<"NS">> => #{}},
ProvID = <<"good-one">>,
ClassID = <<"person">>,
EID = genlib:unique(),
PartyID = create_party(),
Name = <<"Identity Name">>,
ChlClassID = <<"sword-initiation">>,
Identity = create_identity(EID, Name, PartyID, ProvID, ClassID, Context),
IID = Identity#idnt_IdentityState.id,
Params2 = gen_challenge_param(ChlClassID, IID, C),
{ok, _} = call_api('StartChallenge', {IID, Params2}),
Range = #'EventRange'{
limit = 1000,
'after' = undefined
},
FindStatusChanged = fun
(#idnt_Event{change = {identity_challenge, ChallengeChange}}, AccIn) ->
case ChallengeChange#idnt_ChallengeChange.payload of
{status_changed, Status} -> Status;
_Other -> AccIn
end;
(_Ev, AccIn) ->
AccIn
end,
{completed, #idnt_ChallengeCompleted{resolution = approved}} = ct_helper:await(
{completed, #idnt_ChallengeCompleted{resolution = approved}},
fun() ->
{ok, Events} = call_api('GetEvents', {IID, Range}),
lists:foldl(FindStatusChanged, undefined, Events)
end,
genlib_retry:linear(10, 1000)
),
{ok, Identity2} = call_api('Get', {IID, #'EventRange'{}}),
?assertNotEqual(undefined, Identity2#idnt_IdentityState.effective_challenge_id),
?assertNotEqual(undefined, Identity2#idnt_IdentityState.level_id).
get_event_unknown_identity_ok(_C) ->
Ctx = #{<<"NS">> => #{}},
EID = genlib:unique(),
PID = create_party(),
Name = <<"Identity Name">>,
ProvID = <<"good-one">>,
ClassID = <<"person">>,
create_identity(EID, Name, PID, ProvID, ClassID, Ctx),
Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}),
create_identity(EID, Name, PID, ProvID, Ctx, Metadata),
Range = #'EventRange'{
limit = 1,
'after' = undefined
},
{exception, {fistful_IdentityNotFound}} = call_api('GetEvents', {<<"bad id">>, Range}).
start_challenge_token_fail(C) ->
Ctx = #{<<"NS">> => #{}},
EID = genlib:unique(),
PID = create_party(),
Name = <<"Identity Name">>,
ProvID = <<"good-one">>,
CID = <<"person">>,
ChlClassID = <<"sword-initiation">>,
IdentityState = create_identity(EID, Name, PID, ProvID, CID, Ctx),
{Type1, Token1} = ct_identdocstore:rus_retiree_insurance_cert(genlib:unique(), C),
{Type2, _Token2} = ct_identdocstore:rus_domestic_passport(C),
IID = IdentityState#idnt_IdentityState.id,
Proofs = [
#idnt_ChallengeProof{type = Type1, token = Token1},
#idnt_ChallengeProof{type = Type2, token = <<"Token">>}
],
Params = #idnt_ChallengeParams{
id = IID,
cls = ChlClassID,
proofs = Proofs
},
{exception, #fistful_ProofNotFound{}} =
call_api('StartChallenge', {IID, Params}).
get_challenges_ok(C) ->
Context = #{<<"NS">> => nil},
EID = genlib:unique(),
PartyID = create_party(),
ChallengeID = genlib:unique(),
Name = <<"Identity Name">>,
ProvID = <<"good-one">>,
ClassID = <<"person">>,
ChlClassID = <<"sword-initiation">>,
Identity = create_identity(EID, Name, PartyID, ProvID, ClassID, Context),
IID = Identity#idnt_IdentityState.id,
Params2 = gen_challenge_param(ChlClassID, ChallengeID, C),
{ok, Challenge} = call_api('StartChallenge', {IID, Params2}),
{ok, Challenges} = call_api('GetChallenges', {IID}),
CID = Challenge#idnt_ChallengeState.id,
[Chl] = lists:filter(
fun(Item) ->
CID =:= Item#idnt_ChallengeState.id
end,
Challenges
),
?assertEqual(Chl#idnt_ChallengeState.cls, Challenge#idnt_ChallengeState.cls),
?assertEqual(Chl#idnt_ChallengeState.proofs, Challenge#idnt_ChallengeState.proofs).
%%----------
%% INTERNAL
%%----------
create_identity(EID, Name, PartyID, ProvID, ClassID, Ctx) ->
create_identity(EID, Name, PartyID, ProvID, ClassID, Ctx, #{}).
create_identity(EID, Name, PartyID, ProvID, ClassID, Ctx, Metadata) ->
create_identity(EID, Name, PartyID, ProvID, Ctx, Metadata) ->
Params = #idnt_IdentityParams{
id = genlib:unique(),
name = Name,
party = PartyID,
provider = ProvID,
cls = ClassID,
external_id = EID,
metadata = Metadata
},
@ -242,20 +115,6 @@ create_identity(EID, Name, PartyID, ProvID, ClassID, Ctx, Metadata) ->
{ok, IdentityState} = call_api('Create', {Params, Context}),
IdentityState.
gen_challenge_param(ClgClassID, ChallengeID, C) ->
{Type1, Token1} = ct_identdocstore:rus_retiree_insurance_cert(genlib:unique(), C),
{Type2, Token2} = ct_identdocstore:rus_domestic_passport(C),
Proofs = [
#idnt_ChallengeProof{type = Type1, token = Token1},
#idnt_ChallengeProof{type = Type2, token = Token2}
],
#idnt_ChallengeParams{
id = ChallengeID,
cls = ClgClassID,
proofs = Proofs
}.
call_api(Fun, Args) ->
Service = {ff_proto_identity_thrift, 'Management'},
Request = {Service, Fun, Args},

View File

@ -118,7 +118,7 @@ create_source_ok(Resource, C) ->
Name = <<"name">>,
ID = genlib:unique(),
ExternalId = genlib:unique(),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
Ctx = ff_entity_context_codec:marshal(#{<<"NS">> => #{}}),
Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}),
Params = #src_SourceParams{
@ -171,16 +171,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_identity(Party, <<"good-one">>, <<"person">>, C).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -245,7 +245,7 @@ prepare_standard_environment(Body, C) ->
currency = #'CurrencyRef'{symbolic_code = Currency}
} = Body,
Party = create_party(C),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
WalletID1 = create_wallet(IdentityID, <<"My wallet 1">>, Currency, C),
WalletID2 = create_wallet(IdentityID, <<"My wallet 2">>, Currency, C),
ok = await_wallet_balance({0, Currency}, WalletID1),
@ -344,19 +344,16 @@ call_accounter(Function, Args) ->
Service = {shumpune_shumpune_thrift, 'Accounter'},
ff_woody_client:call(accounter, {Service, Function, Args}, woody_context:new()).
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"quote-owner">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-two">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -90,7 +90,7 @@ create_ok(C) ->
Currency = <<"RUB">>,
ID = genlib:unique(),
ExternalID = genlib:unique(),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
Ctx = #{<<"TEST_NS">> => {obj, #{{str, <<"KEY">>} => {b, true}}}},
Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}),
Params = construct_wallet_params(ID, IdentityID, Currency, ExternalID, Metadata),
@ -121,7 +121,7 @@ create_error_currency_not_found(C) ->
Party = create_party(C),
Currency = <<"RBK.MONEY">>,
ID = genlib:unique(),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
Params = construct_wallet_params(ID, IdentityID, Currency),
Result = call_service('Create', {Params, #{}}),
?assertMatch({exception, #fistful_CurrencyNotFound{}}, Result).
@ -130,7 +130,7 @@ create_error_party_blocked(C) ->
Party = create_party(C),
Currency = <<"RUB">>,
ID = genlib:unique(),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
ok = block_party(Party, C),
Params = construct_wallet_params(ID, IdentityID, Currency),
Result = call_service('Create', {Params, #{}}),
@ -140,7 +140,7 @@ create_error_party_suspended(C) ->
Party = create_party(C),
Currency = <<"RUB">>,
ID = genlib:unique(),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
ok = suspend_party(Party, C),
Params = construct_wallet_params(ID, IdentityID, Currency),
Result = call_service('Create', {Params, #{}}),
@ -151,7 +151,7 @@ get_account_balance(C) ->
Currency = <<"RUB">>,
ID = genlib:unique(),
ExternalID = genlib:unique(),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
Ctx = #{<<"TEST_NS">> => {obj, #{{str, <<"KEY">>} => {b, true}}}},
Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}),
Params = construct_wallet_params(ID, IdentityID, Currency, ExternalID, Metadata),
@ -184,16 +184,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_identity(Party, <<"good-one">>, <<"person">>, C).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -481,7 +481,7 @@ prepare_standard_environment(Body, Token, C) ->
currency = #'CurrencyRef'{symbolic_code = Currency}
} = Body,
Party = create_party(C),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
WalletID = create_wallet(IdentityID, <<"My wallet">>, Currency, C),
ok = await_wallet_balance({0, Currency}, WalletID),
DestinationID = create_destination(IdentityID, Token, C),
@ -555,19 +555,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -129,15 +129,12 @@ create_party(_C) ->
ID.
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, <<"person">>, C).
create_identity(Party, <<"Owner">>, <<"good-one">>, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -341,25 +341,9 @@ create_callback(Tag, Session) ->
-spec convert_identity_state_to_adapter_identity(ff_identity:identity_state()) -> ff_adapter_withdrawal:identity().
convert_identity_state_to_adapter_identity(IdentityState) ->
Identity = #{
#{
id => ff_identity:id(IdentityState)
},
case ff_identity:effective_challenge(IdentityState) of
{ok, ChallengeID} ->
case ff_identity:challenge(ChallengeID, IdentityState) of
{ok, Challenge} ->
Identity#{
effective_challenge => #{
id => ChallengeID,
proofs => ff_identity_challenge:proofs(Challenge)
}
};
_ ->
Identity
end;
_ ->
Identity
end.
}.
-spec get_adapter_with_opts(ff_withdrawal_routing:route()) -> adapter_with_opts().
get_adapter_with_opts(Route) ->

View File

@ -250,7 +250,7 @@ unknown_test(_C) ->
prepare_standard_environment(Currency, C) ->
Party = create_party(C),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
WalletID = create_wallet(IdentityID, <<"My wallet">>, <<"RUB">>, C),
ok = await_wallet_balance({0, Currency}, WalletID),
SourceID = create_source(IdentityID, C),
@ -290,19 +290,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -298,7 +298,7 @@ unknown_deposit_test(_C) ->
prepare_standard_environment({_Amount, Currency} = DepositCash, C) ->
Party = create_party(C),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
WalletID = create_wallet(IdentityID, <<"My wallet">>, <<"RUB">>, C),
ok = await_wallet_balance({0, Currency}, WalletID),
SourceID = create_source(IdentityID, C),
@ -383,19 +383,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -312,7 +312,7 @@ unknown_deposit_test(_C) ->
prepare_standard_environment({_Amount, Currency} = Cash, C) ->
Party = create_party(C),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
WalletID = create_wallet(IdentityID, <<"My wallet">>, <<"RUB">>, C),
ok = await_wallet_balance({0, Currency}, WalletID),
SourceID = create_source(IdentityID, C),
@ -389,19 +389,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -321,7 +321,7 @@ unknown_revert_test(C) ->
prepare_standard_environment({_Amount, Currency} = DepositCash, RevertCash, C) ->
Party = create_party(C),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
WalletID = create_wallet(IdentityID, <<"My wallet">>, <<"RUB">>, C),
ok = await_wallet_balance({0, Currency}, WalletID),
SourceID = create_source(IdentityID, C),
@ -438,19 +438,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -85,7 +85,7 @@ end_per_testcase(_Name, _C) ->
-spec create_destination_ok_test(config()) -> test_return().
create_destination_ok_test(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
BankCard = ct_cardstore:bank_card(<<"4150399999000900">>, {12, 2025}, C),
_DestinationID = create_destination(IID, BankCard),
ok.
@ -116,7 +116,7 @@ create_destination_identity_notfound_fail_test(C) ->
-spec create_destination_currency_notfound_fail_test(config()) -> test_return().
create_destination_currency_notfound_fail_test(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
DestResource = {
bank_card,
#{
@ -140,7 +140,7 @@ create_destination_currency_notfound_fail_test(C) ->
-spec get_destination_ok_test(config()) -> test_return().
get_destination_ok_test(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
BankCard = ct_cardstore:bank_card(<<"4150399999000900">>, {12, 2025}, C),
DestinationID = create_destination(IID, BankCard),
{ok, DestinationMachine} = ff_destination_machine:get(DestinationID),
@ -165,19 +165,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -86,7 +86,7 @@ end_per_testcase(_Name, _C) ->
-spec create_source_ok_test(config()) -> test_return().
create_source_ok_test(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
_SourceID = create_source(IID, C),
ok.
@ -107,7 +107,7 @@ create_source_identity_notfound_fail_test(_C) ->
-spec create_source_currency_notfound_fail_test(config()) -> test_return().
create_source_currency_notfound_fail_test(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
SrcResource = #{type => internal, details => <<"Infinite source of cash">>},
Params = #{
id => genlib:unique(),
@ -122,7 +122,7 @@ create_source_currency_notfound_fail_test(C) ->
-spec get_source_ok_test(config()) -> test_return().
get_source_ok_test(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
SourceID = create_source(IID, C),
{ok, SourceMachine} = ff_source_machine:get(SourceID),
?assertMatch(
@ -146,19 +146,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -102,7 +102,7 @@ get_missing_fails(_C) ->
deposit_via_admin_ok(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
WalID = create_wallet(IID, <<"HAHA NO">>, <<"RUB">>, C),
ok = await_wallet_balance({0, <<"RUB">>}, WalID),
SrcID = genlib:unique(),
@ -160,7 +160,7 @@ deposit_via_admin_ok(C) ->
deposit_via_admin_fails(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
WalID = create_wallet(IID, <<"HAHA NO">>, <<"RUB">>, C),
ok = await_wallet_balance({0, <<"RUB">>}, WalID),
SrcID = genlib:unique(),
@ -218,7 +218,7 @@ deposit_via_admin_fails(C) ->
deposit_via_admin_amount_fails(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
WalID = create_wallet(IID, <<"HAHA NO">>, <<"RUB">>, C),
ok = await_wallet_balance({0, <<"RUB">>}, WalID),
SrcID = genlib:unique(),
@ -264,7 +264,7 @@ deposit_via_admin_amount_fails(C) ->
deposit_via_admin_currency_fails(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
IID = create_identity(Party, C),
WalID = create_wallet(IID, <<"HAHA NO">>, <<"RUB">>, C),
ok = await_wallet_balance({0, <<"RUB">>}, WalID),
SrcID = genlib:unique(),
@ -311,56 +311,48 @@ deposit_via_admin_currency_fails(C) ->
deposit_withdrawal_ok(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
ICID = genlib:unique(),
IID = create_identity(Party, C),
WalID = create_wallet(IID, <<"HAHA NO">>, <<"RUB">>, C),
ok = await_wallet_balance({0, <<"RUB">>}, WalID),
SrcID = create_source(IID, C),
ok = process_deposit(SrcID, WalID),
DestID = create_destination(IID, C),
ok = pass_identification(ICID, IID, C),
WdrID = process_withdrawal(WalID, DestID),
Events = get_withdrawal_events(WdrID),
[1] = route_changes(Events).
deposit_withdrawal_to_crypto_wallet(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
ICID = genlib:unique(),
IID = create_identity(Party, C),
WalID = create_wallet(IID, <<"WalletName">>, <<"RUB">>, C),
ok = await_wallet_balance({0, <<"RUB">>}, WalID),
SrcID = create_source(IID, C),
ok = process_deposit(SrcID, WalID),
DestID = create_crypto_destination(IID, C),
ok = pass_identification(ICID, IID, C),
WdrID = process_withdrawal(WalID, DestID),
Events = get_withdrawal_events(WdrID),
[2] = route_changes(Events).
deposit_withdrawal_to_digital_wallet(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C, <<"quote-owner">>),
ICID = genlib:unique(),
IID = create_identity(Party, <<"good-two">>, C),
WalID = create_wallet(IID, <<"WalletName">>, <<"RUB">>, C),
ok = await_wallet_balance({0, <<"RUB">>}, WalID),
SrcID = create_source(IID, C),
ok = process_deposit(SrcID, WalID),
DestID = create_digital_destination(IID, C),
ok = pass_identification(ICID, IID, C),
WdrID = process_withdrawal(WalID, DestID),
Events = get_withdrawal_events(WdrID),
[3] = route_changes(Events).
deposit_quote_withdrawal_ok(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C, <<"quote-owner">>),
ICID = genlib:unique(),
IID = create_identity(Party, <<"good-two">>, C),
WalID = create_wallet(IID, <<"HAHA NO">>, <<"RUB">>, C),
ok = await_wallet_balance({0, <<"RUB">>}, WalID),
SrcID = create_source(IID, C),
ok = process_deposit(SrcID, WalID),
DestID = create_destination(IID, C),
ok = pass_identification(ICID, IID, C),
DomainRevision = ff_domain_config:head(),
{ok, PartyRevision} = ff_party:get_revision(Party),
WdrID = process_withdrawal(WalID, DestID, #{
@ -387,19 +379,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.
@ -554,27 +543,6 @@ create_digital_destination(IID, _C) ->
),
DestID.
pass_identification(ICID, IID, C) ->
Doc1 = ct_identdocstore:rus_retiree_insurance_cert(genlib:unique(), C),
Doc2 = ct_identdocstore:rus_domestic_passport(C),
ok = ff_identity_machine:start_challenge(
IID,
#{
id => ICID,
class => <<"sword-initiation">>,
proofs => [Doc1, Doc2]
}
),
{completed, _} = ct_helper:await(
{completed, #{resolution => approved}},
fun() ->
{ok, S} = ff_identity_machine:get(IID),
{ok, IC} = ff_identity:challenge(ICID, ff_identity_machine:identity(S)),
ff_identity_challenge:status(IC)
end
),
ok.
process_withdrawal(WalID, DestID) ->
process_withdrawal(WalID, DestID, #{wallet_id => WalID, destination_id => DestID, body => {4240, <<"RUB">>}}).

View File

@ -162,7 +162,7 @@ session_fail_test(C) ->
Party = create_party(C),
Currency = <<"RUB">>,
WithdrawalCash = {100, Currency},
IdentityID = create_person_identity(Party, C, <<"quote-owner">>),
IdentityID = create_identity(Party, <<"good-two">>, C),
WalletID = create_wallet(IdentityID, <<"My wallet">>, Currency, C),
ok = await_wallet_balance({0, Currency}, WalletID),
DestinationID = create_destination(IdentityID, undefined, C),
@ -382,7 +382,7 @@ create_identity_providers_mismatch_error_test(C) ->
destination_id := DestinationID
} = prepare_standard_environment(Cash, C),
Party = create_party(C),
IdentityID = create_identity(Party, <<"good-two">>, <<"person">>, C),
IdentityID = create_identity(Party, <<"good-two">>, C),
WalletID = create_wallet(IdentityID, <<"My wallet">>, <<"RUB">>, C),
WithdrawalID = generate_id(),
WithdrawalParams = #{
@ -498,7 +498,7 @@ crypto_quota_ok_test(C) ->
Currency = <<"RUB">>,
Cash = {100, Currency},
Party = create_party(C),
IdentityID = create_person_identity(Party, C, <<"quote-owner">>),
IdentityID = create_identity(Party, <<"good-two">>, C),
WalletID = create_wallet(IdentityID, <<"My wallet">>, Currency, C),
ok = await_wallet_balance({0, Currency}, WalletID),
DestinationID = create_crypto_destination(IdentityID, C),
@ -835,18 +835,15 @@ create_party(_C) ->
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -299,7 +299,7 @@ unknown_withdrawal_test(_C) ->
prepare_standard_environment({_Amount, Currency} = WithdrawalCash, C) ->
Party = create_party(C),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
WalletID = create_wallet(IdentityID, <<"My wallet">>, <<"RUB">>, C),
ok = await_wallet_balance({0, Currency}, WalletID),
DestinationID = create_destination(IdentityID, C),
@ -385,19 +385,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -279,7 +279,7 @@ await_final_withdrawal_status(WithdrawalID) ->
prepare_standard_environment({_Amount, Currency} = WithdrawalCash, C) ->
Party = create_party(C),
IdentityID = create_person_identity(Party, C),
IdentityID = create_identity(Party, C),
WalletID = create_wallet(IdentityID, <<"My wallet">>, Currency, C),
ok = await_wallet_balance({0, Currency}, WalletID),
DestinationID = create_destination(IdentityID, Currency, C),
@ -296,19 +296,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -21,13 +21,7 @@
-type party_id() :: ff_party:id().
-type provider_id() :: ff_provider:id().
-type contract_id() :: ff_party:contract_id().
-type class_id() :: ff_identity_class:id().
-type challenge_class() :: ff_identity_challenge:challenge_class().
-type challenge_class_id() :: ff_identity_class:challenge_class_id().
-type challenge_id() :: id().
-type blocking() :: unblocked | blocked.
-type level() :: ff_identity_class:level().
-type level_id() :: ff_identity_class:level_id().
-type metadata() :: ff_entity_context:md().
-define(ACTUAL_FORMAT_VERSION, 2).
@ -37,11 +31,7 @@
name := name(),
party := party_id(),
provider := provider_id(),
class := class_id(),
contract := contract_id(),
level => level_id(),
challenges => #{challenge_id() => challenge()},
effective => challenge_id(),
external_id => id(),
blocking => blocking(),
metadata => metadata(),
@ -54,28 +44,29 @@
name := name(),
party := party_id(),
provider := provider_id(),
class := class_id(),
contract := contract_id(),
external_id => id(),
metadata => metadata(),
created_at => ff_time:timestamp_ms()
}.
-type challenge() ::
ff_identity_challenge:challenge_state().
-type event() ::
{created, identity()}
| {level_changed, level_id()}
| {effective_challenge_changed, challenge_id()}
| {{challenge, challenge_id()}, ff_identity_challenge:event()}.
| {{challenge, challenge_id()}, challenge_event()}.
-type level_id() :: binary().
-type challenge_id() :: id().
-type challenge_event() ::
{created, any()}
| {status_changed, any()}.
-type params() :: #{
id := id(),
name := name(),
party := ff_party:id(),
provider := ff_provider:id(),
class := ff_identity:class_id(),
external_id => id(),
metadata => metadata()
}.
@ -83,37 +74,21 @@
-type create_error() ::
{provider, notfound}
| {party, notfound}
| {identity_class, notfound}
| ff_party:inaccessibility()
| invalid.
-type start_challenge_error() ::
exists
| {challenge_class, notfound}
| {level, level()}
| ff_identity_challenge:create_error().
-export_type([identity/0]).
-export_type([identity_state/0]).
-export_type([event/0]).
-export_type([id/0]).
-export_type([create_error/0]).
-export_type([start_challenge_error/0]).
-export_type([challenge_class_id/0]).
-export_type([class_id/0]).
-export_type([level_id/0]).
-export_type([params/0]).
-export([id/1]).
-export([name/1]).
-export([provider/1]).
-export([party/1]).
-export([class/1]).
-export([level/1]).
-export([contract/1]).
-export([challenges/1]).
-export([challenge/2]).
-export([effective_challenge/1]).
-export([external_id/1]).
-export([blocking/1]).
-export([created_at/1]).
@ -124,28 +99,20 @@
-export([create/1]).
-export([start_challenge/4]).
-export([poll_challenge_completion/2]).
-export([apply_event/2]).
%% Pipeline
-import(ff_pipeline, [do/1, unwrap/1, unwrap/2, expect/2, flip/1, valid/2]).
-import(ff_pipeline, [do/1, unwrap/1, unwrap/2]).
%% Accessors
-spec id(identity_state()) -> id().
-spec name(identity_state()) -> name().
-spec provider(identity_state()) -> provider_id().
-spec class(identity_state()) -> class_id().
-spec party(identity_state()) -> party_id().
-spec contract(identity_state()) -> contract_id().
-spec blocking(identity_state()) -> boolean() | undefined.
-spec level(identity_state()) -> level_id() | undefined.
-spec challenges(identity_state()) -> #{challenge_id() => challenge()}.
-spec effective_challenge(identity_state()) -> ff_map:result(challenge_id()).
-spec challenge(challenge_id(), identity_state()) -> ff_map:result(challenge()).
-spec external_id(identity_state()) -> external_id().
-spec created_at(identity_state()) -> ff_time:timestamp_ms() | undefined.
-spec metadata(identity_state()) -> metadata() | undefined.
@ -159,9 +126,6 @@ name(#{name := V}) ->
provider(#{provider := V}) ->
V.
class(#{class := V}) ->
V.
party(#{party := V}) ->
V.
@ -171,18 +135,6 @@ contract(#{contract := V}) ->
blocking(Identity) ->
maps:get(blocking, Identity, undefined).
level(Identity) ->
maps:get(level, Identity, undefined).
challenges(Identity) ->
maps:get(challenges, Identity, #{}).
effective_challenge(Identity) ->
ff_map:find(effective, Identity).
challenge(ChallengeID, Identity) ->
ff_map:find(ChallengeID, challenges(Identity)).
external_id(Identity) ->
maps:get(external_id, Identity, undefined).
@ -214,18 +166,15 @@ set_blocking(Identity) ->
-spec create(params()) ->
{ok, [event()]}
| {error, create_error()}.
create(Params = #{id := ID, name := Name, party := Party, provider := ProviderID, class := ClassID}) ->
create(Params = #{id := ID, name := Name, party := Party, provider := ProviderID}) ->
do(fun() ->
accessible = unwrap(party, ff_party:is_accessible(Party)),
Provider = unwrap(provider, ff_provider:get(ProviderID)),
Class = unwrap(identity_class, ff_provider:get_identity_class(ClassID, Provider)),
LevelID = ff_identity_class:initial_level(Class),
{ok, Level} = ff_identity_class:level(LevelID, Class),
Contract = unwrap(
ff_party:create_contract(Party, #{
payinst => ff_provider:payinst(Provider),
contract_template => ff_identity_class:contract_template(Class),
contractor_level => ff_identity_class:contractor_level(Level)
contract_template => ff_provider:contract_template(Provider),
contractor_level => ff_provider:contractor_level(Provider)
})
),
[
@ -236,116 +185,22 @@ create(Params = #{id := ID, name := Name, party := Party, provider := ProviderID
name => Name,
party => Party,
provider => ProviderID,
class => ClassID,
contract => Contract,
created_at => ff_time:now(),
external_id => maps:get(external_id, Params, undefined),
metadata => maps:get(metadata, Params, undefined)
})},
{level_changed, LevelID}
})}
]
end).
%%
-spec start_challenge(challenge_id(), challenge_class(), [ff_identity_challenge:proof()], identity_state()) ->
{ok, [event()]}
| {error, start_challenge_error()}.
start_challenge(ChallengeID, ChallengeClassID, Proofs, Identity) ->
do(fun() ->
notfound = expect(exists, flip(challenge(ChallengeID, Identity))),
IdentityClass = get_identity_class(Identity),
ChallengeClass = unwrap(
challenge_class,
ff_identity_class:challenge_class(
ChallengeClassID,
IdentityClass
)
),
ok = unwrap(level, valid(ff_identity_class:base_level(ChallengeClass), level(Identity))),
Events = unwrap(
ff_identity_challenge:create(
ChallengeID,
id(Identity),
provider(Identity),
class(Identity),
ChallengeClassID,
Proofs
)
),
[{{challenge, ChallengeID}, Ev} || Ev <- Events]
end).
-spec poll_challenge_completion(challenge_id(), identity_state()) ->
{ok, [event()]}
| {error,
notfound
| ff_identity_challenge:status()}.
poll_challenge_completion(ChallengeID, Identity) ->
do(fun() ->
Challenge = unwrap(challenge(ChallengeID, Identity)),
case unwrap(ff_identity_challenge:poll_completion(Challenge)) of
[] ->
[];
Events = [_ | _] ->
Contract = contract(Identity),
IdentityClass = get_identity_class(Identity),
ChallengeClass = get_challenge_class(Challenge, Identity),
TargetLevelID = ff_identity_class:target_level(ChallengeClass),
{ok, Level} = ff_identity_class:level(TargetLevelID, IdentityClass),
ok = unwrap(
ff_party:change_contractor_level(
party(Identity),
Contract,
ff_identity_class:contractor_level(Level)
)
),
[{{challenge, ChallengeID}, Ev} || Ev <- Events] ++
[
{level_changed, TargetLevelID},
{effective_challenge_changed, ChallengeID}
]
end
end).
get_provider(Identity) ->
{ok, V} = ff_provider:get(provider(Identity)),
V.
get_identity_class(Identity) ->
{ok, V} = ff_provider:get_identity_class(class(Identity), get_provider(Identity)),
V.
get_challenge_class(Challenge, Identity) ->
{ok, V} = ff_identity_class:challenge_class(
ff_identity_challenge:class(Challenge),
get_identity_class(Identity)
),
V.
%%
-spec apply_event(event(), ff_maybe:maybe(identity_state())) -> identity_state().
apply_event({created, Identity}, undefined) ->
Identity;
apply_event({level_changed, L}, Identity) ->
Identity#{level => L};
apply_event({effective_challenge_changed, ID}, Identity) ->
Identity#{effective => ID};
apply_event({{challenge, ID}, Ev}, Identity) ->
with_challenges(
fun(Cs) ->
with_challenge(
ID,
fun(C) -> ff_identity_challenge:apply_event(Ev, C) end,
Cs
)
end,
Identity
).
with_challenges(Fun, Identity) ->
maps:update_with(challenges, Fun, maps:merge(#{challenges => #{}}, Identity)).
with_challenge(ID, Fun, Challenges) ->
maps:update_with(ID, Fun, maps:merge(#{ID => undefined}, Challenges)).
apply_event({level_changed, _L}, Identity) ->
Identity;
apply_event({effective_challenge_changed, _ID}, Identity) ->
Identity;
apply_event({{challenge, _ID}, _Ev}, Identity) ->
Identity.

View File

@ -1,315 +0,0 @@
%%%
%%% Identity challenge activity
%%%
%%% TODOs
%%%
%%% - `ProviderID` + `IdentityClassID` + `ChallengeClassID` easily replaceable
%%% with a _single_ identifier if we drop strictly hierarchical provider
%%% definition.
%%%
-module(ff_identity_challenge).
%% API
-type id(T) :: T.
-type claimant() :: id(binary()).
-type timestamp() :: machinery:timestamp().
-type provider() :: ff_provider:id().
-type identity_class() :: ff_identity_class:id().
-type challenge_class_id() :: ff_identity_class:challenge_class_id().
-type master_id() :: id(binary()).
-type claim_id() :: id(binary()).
-type challenge_state() :: #{
id := id(_),
claimant := claimant(),
provider := provider(),
identity_class := identity_class(),
challenge_class := challenge_class_id(),
proofs := [proof()],
master_id := master_id(),
claim_id := claim_id(),
status := status()
}.
-type challenge() :: #{
id := id(_),
claimant := claimant(),
provider := provider(),
identity_class := identity_class(),
challenge_class := challenge_class_id(),
proofs := [proof()],
master_id := master_id(),
claim_id := claim_id()
}.
-type level_id() :: ff_identity_class:level_id().
-type challenge_class() :: #{
id := challenge_class_id(),
name := binary(),
base_level := level_id(),
target_level := level_id()
}.
-type proof() ::
{proof_type(), identdoc_token()}.
-type proof_type() ::
rus_domestic_passport
| rus_retiree_insurance_cert.
-type identdoc_token() ::
binary().
-type status() ::
pending
| {completed, completion()}
| {failed, failure()}
| cancelled.
-type completion() :: #{
resolution := resolution(),
valid_until => timestamp()
}.
-type resolution() ::
approved
| denied.
-type failure() ::
_TODO.
-type event() ::
{created, challenge()}
| {status_changed, status()}.
-type create_error() ::
{proof, notfound | insufficient}
| pending
| conflict.
-export_type([challenge/0]).
-export_type([challenge_state/0]).
-export_type([event/0]).
-export_type([create_error/0]).
-export_type([proof/0]).
-export_type([id/1]).
-export_type([status/0]).
-export_type([challenge_class/0]).
-export_type([level_id/0]).
-export([id/1]).
-export([claimant/1]).
-export([status/1]).
-export([class/1]).
-export([proofs/1]).
-export([resolution/1]).
-export([claim_id/1]).
-export([master_id/1]).
-export([create/6]).
-export([poll_completion/1]).
-export([apply_event/2]).
%% Pipeline
-import(ff_pipeline, [do/1, unwrap/1, valid/2]).
%%
-spec id(challenge_state()) -> id(_).
id(#{id := V}) ->
V.
-spec status(challenge_state()) -> status() | undefined.
status(Challenge) ->
maps:get(status, Challenge, undefined).
-spec claimant(challenge_state()) -> claimant().
claimant(#{claimant := V}) ->
V.
-spec class(challenge_state()) -> challenge_class_id().
class(#{challenge_class := V}) ->
V.
-spec proofs(challenge_state()) -> [proof()].
proofs(#{proofs := V}) ->
V.
-spec resolution(challenge_state()) ->
{ok, resolution()}
| {error, undefined}.
resolution(Challenge) ->
case status(Challenge) of
{completed, #{resolution := Resolution}} ->
{ok, Resolution};
_Status ->
{error, undefined}
end.
-spec master_id(challenge_state()) -> id(_).
master_id(#{master_id := V}) ->
V.
-spec claim_id(challenge_state()) -> id(_).
claim_id(#{claim_id := V}) ->
V.
%%
-spec create(id(_), claimant(), provider(), identity_class(), challenge_class_id(), [proof()]) ->
{ok, [event()]}
| {error, create_error()}.
create(ID, Claimant, ProviderID, IdentityClassID, ChallengeClassID, Proofs) ->
do(fun() ->
{ok, Provider} = ff_provider:get(ProviderID),
{ok, IdentityClass} = ff_provider:get_identity_class(IdentityClassID, Provider),
{ok, ChallengeClass} = ff_identity_class:challenge_class(ChallengeClassID, IdentityClass),
TargetLevelID = ff_identity_class:target_level(ChallengeClass),
{ok, TargetLevel} = ff_identity_class:level(TargetLevelID, IdentityClass),
MasterID = unwrap(deduce_identity_id(Proofs)),
ClaimID = unwrap(create_claim(MasterID, TargetLevel, Claimant, Proofs)),
[
{created, #{
id => ID,
claimant => Claimant,
provider => ProviderID,
identity_class => IdentityClassID,
challenge_class => ChallengeClassID,
proofs => Proofs,
master_id => MasterID,
claim_id => ClaimID
}},
{status_changed, pending}
]
end).
-spec poll_completion(challenge_state()) ->
{ok, [event()]}
| {error,
notfound
| status()}.
poll_completion(Challenge) ->
do(fun() ->
ok = unwrap(valid(pending, status(Challenge))),
Status = unwrap(get_claim_status(claim_id(Challenge))),
case Status of
created ->
[];
approved ->
[{status_changed, {completed, #{resolution => approved}}}];
denied ->
[{status_changed, {completed, #{resolution => denied}}}];
{failed, Failure} ->
[{status_changed, {failed, Failure}}];
cancelled ->
[{status_changed, cancelled}]
end
end).
%%
-spec apply_event(event(), ff_maybe:maybe(challenge_state())) -> challenge_state().
apply_event({created, Challenge}, undefined) ->
Challenge;
apply_event({status_changed, S}, Challenge) ->
Challenge#{status => S}.
%%
-include_lib("id_proto/include/id_proto_identification_thrift.hrl").
deduce_identity_id(Proofs) ->
case call('GetIdentityID', {encode({list, identity_document}, Proofs)}) of
{ok, IdentityID} ->
{ok, decode(identity_id, IdentityID)};
{exception, #identity_IdentityDocumentNotFound{}} ->
{error, {proof, notfound}};
{exception, #identity_InsufficientIdentityDocuments{}} ->
{error, {proof, insufficient}}
end.
create_claim(MasterID, TargetLevel, Claimant, Proofs) ->
case call('CreateClaim', {encode(identity_claim_params, {MasterID, TargetLevel, Claimant, Proofs})}) of
{ok, #identity_IdentityClaim{id = ID}} ->
{ok, decode(identity_claim_id, ID)};
{exception, #identity_ClaimPending{}} ->
{error, pending};
{exception, #identity_InsufficientIdentityDocuments{}} ->
{error, {proof, insufficient}};
{exception, #identity_IdentityOwnershipConflict{}} ->
{error, conflict};
{exception, Unexpected} ->
error(Unexpected)
end.
get_claim_status(ClaimID) ->
case call('GetClaim', {encode(identity_claim_id, ClaimID)}) of
{ok, #identity_IdentityClaim{status = Status}} ->
{ok, decode(identity_claim_status, Status)};
{exception, #identity_ClaimNotFound{}} ->
{error, notfound}
end.
encode(identity_claim_params, {MasterID, TargetLevel, Claimant, Proofs}) ->
#identity_IdentityClaimParams{
identity_id = encode(identity_id, MasterID),
target_level = encode(level, ff_identity_class:contractor_level(TargetLevel)),
claimant = encode(claimant, Claimant),
proof = encode({list, identity_document}, Proofs)
};
encode(level, Level) ->
% TODO
Level;
encode(identity_document, {Type, Token}) ->
#identity_IdentityDocument{
type = encode(identity_document_type, Type),
token = encode(string, Token)
};
encode(identity_document_type, rus_domestic_passport) ->
{rus_domestic_passport, #identity_RUSDomesticPassport{}};
encode(identity_document_type, rus_retiree_insurance_cert) ->
{rus_retiree_insurance_cert, #identity_RUSRetireeInsuranceCert{}};
encode(identity_claim_id, V) ->
encode(string, V);
encode(identity_id, V) ->
encode(string, V);
encode(claimant, V) ->
encode(string, V);
encode({list, T}, V) when is_list(V) ->
[encode(T, E) || E <- V];
encode(string, V) when is_binary(V) ->
V.
%%
decode(identity_claim_status, {created, _}) ->
created;
decode(identity_claim_status, {review, _}) ->
review;
decode(identity_claim_status, {approved, _}) ->
approved;
decode(identity_claim_status, {denied, _}) ->
denied;
decode(identity_claim_status, {cancelled, _}) ->
cancelled;
decode(identity_claim_status, {failed, Failure}) ->
{failed, Failure};
decode(identity_claim_id, V) ->
decode(string, V);
decode(identity_id, V) ->
decode(string, V);
decode(string, V) when is_binary(V) ->
V.
%%
call(Function, Args) ->
% TODO
% - Ideally, we should provide `Client` here explicitly.
Service = {id_proto_identification_thrift, 'Identification'},
ff_woody_client:call(identification, {Service, Function, Args}).

View File

@ -1,110 +0,0 @@
%%%
%%% Identity class
%%%
-module(ff_identity_class).
%%
-type id() :: binary().
%%
-type challenge_class_id() :: binary().
-type challenge_class() :: ff_identity_challenge:challenge_class().
-type contractor_level() ::
dmsl_domain_thrift:'ContractorIdentificationLevel'().
-type level() :: #{
id := level_id(),
name := binary(),
contractor_level := contractor_level()
}.
-type contract_template_ref() ::
dmsl_domain_thrift:'ContractTemplateRef'().
-type level_id() :: binary().
-type class() :: #{
id := id(),
name := binary(),
contract_template_ref := contract_template_ref(),
initial_level := level_id(),
levels := #{level_id() => level()},
challenge_classes := #{challenge_class_id() => challenge_class()}
}.
-export([id/1]).
-export([name/1]).
-export([contract_template/1]).
-export([initial_level/1]).
-export([level/2]).
-export([level_name/1]).
-export([contractor_level/1]).
-export([challenge_class/2]).
-export([base_level/1]).
-export([target_level/1]).
-export([challenge_class_name/1]).
-export_type([id/0]).
-export_type([challenge_class_id/0]).
-export_type([level_id/0]).
-export_type([level/0]).
-export_type([class/0]).
%% Class
-spec id(class()) -> id().
id(#{id := V}) ->
V.
-spec name(class()) -> binary().
name(#{name := V}) ->
V.
-spec contract_template(class()) -> contract_template_ref().
contract_template(#{contract_template_ref := V}) ->
V.
-spec initial_level(class()) -> level_id().
initial_level(#{initial_level := V}) ->
V.
-spec level(level_id(), class()) ->
{ok, level()}
| {error, notfound}.
level(ID, #{levels := Levels}) ->
ff_map:find(ID, Levels).
-spec challenge_class(challenge_class_id(), class()) ->
{ok, challenge_class()}
| {error, notfound}.
challenge_class(ID, #{challenge_classes := ChallengeClasses}) ->
ff_map:find(ID, ChallengeClasses).
%% Level
-spec level_name(level()) -> binary().
level_name(#{name := V}) ->
V.
-spec contractor_level(level()) -> contractor_level().
contractor_level(#{contractor_level := V}) ->
V.
%% Challenge
-spec challenge_class_name(challenge_class()) -> binary().
challenge_class_name(#{name := V}) ->
V.
-spec base_level(challenge_class()) -> level_id().
base_level(#{base_level := V}) ->
V.
-spec target_level(challenge_class()) -> level_id().
target_level(#{target_level := V}) ->
V.

View File

@ -25,18 +25,10 @@
-type st() :: ff_machine:st(identity()).
-type challenge_id() ::
machinery:id().
-type start_challenge_error() ::
{challenge, {pending, challenge_id()}}
| {challenge, ff_identity:start_challenge_error()}.
-type repair_error() :: ff_repair:repair_error().
-type repair_response() :: ff_repair:repair_response().
-export_type([id/0]).
-export_type([challenge_params/0]).
-export_type([params/0]).
-export_type([repair_error/0]).
-export_type([repair_response/0]).
@ -46,8 +38,6 @@
-export([get/2]).
-export([events/2]).
-export([start_challenge/2]).
%% Accessors
-export([identity/1]).
@ -64,7 +54,7 @@
%% Pipeline
-import(ff_pipeline, [do/1, do/2, unwrap/1]).
-import(ff_pipeline, [do/1, unwrap/1]).
-define(NS, 'ff/identity').
@ -102,25 +92,6 @@ events(ID, {After, Limit}) ->
[{EventID, TsEv} || {EventID, _, TsEv} <- History]
end).
-type challenge_params() :: #{
id := challenge_id(),
class := ff_identity_class:challenge_class_id(),
proofs := [ff_identity_challenge:proof()]
}.
-spec start_challenge(id(), challenge_params()) ->
ok
| {error,
notfound
| start_challenge_error()}.
start_challenge(ID, Params) ->
case machinery:call(?NS, ID, {start_challenge, Params}, backend()) of
{ok, Reply} ->
Reply;
Error ->
Error
end.
backend() ->
fistful:backend(?NS).
@ -154,77 +125,21 @@ init({Events, Ctx}, #{}, _, _Opts) ->
%%
-spec process_timeout(machine(), _, handler_opts()) -> result().
process_timeout(Machine, _, _Opts) ->
St = ff_machine:collapse(ff_identity, Machine),
process_activity(deduce_activity(identity(St)), St).
process_activity({challenge, ChallengeID}, St) ->
Identity = identity(St),
{ok, Events} = ff_identity:poll_challenge_completion(ChallengeID, Identity),
case Events of
[] ->
#{action => set_poll_timer(St)};
_Some ->
#{events => ff_machine:emit_events(Events)}
end.
set_poll_timer(St) ->
Now = machinery_time:now(),
Timeout = erlang:max(1, machinery_time:interval(Now, ff_machine:updated(St)) div 1000),
{set_timer, {timeout, Timeout}}.
process_timeout(_Machine, _, _Opts) ->
#{}.
%%
-type call() ::
{start_challenge, challenge_params()}.
-type call() :: term().
-spec process_call(call(), machine(), handler_args(), handler_opts()) ->
{ok | {error, start_challenge_error()}, result()}.
process_call({start_challenge, Params}, Machine, _Args, _Opts) ->
St = ff_machine:collapse(ff_identity, Machine),
case deduce_activity(identity(St)) of
undefined ->
do_start_challenge(Params, St);
{challenge, ChallengeID} ->
handle_result({error, {challenge, {pending, ChallengeID}}})
end.
{ok, result()}.
process_call(_Call, _Machine, _Args, _Opts) ->
{ok, #{}}.
-spec process_repair(ff_repair:scenario(), machine(), handler_args(), handler_opts()) ->
{ok, {repair_response(), result()}} | {error, repair_error()}.
process_repair(Scenario, Machine, _Args, _Opts) ->
ff_repair:apply_scenario(ff_identity, Machine, Scenario).
do_start_challenge(Params, St) ->
Identity = identity(St),
handle_result(
do(challenge, fun() ->
#{
id := ChallengeID,
class := ChallengeClassID,
proofs := Proofs
} = Params,
Events = unwrap(ff_identity:start_challenge(ChallengeID, ChallengeClassID, Proofs, Identity)),
#{
events => ff_machine:emit_events(Events),
action => continue
}
end)
).
handle_result({ok, R}) ->
{ok, R};
handle_result({error, _} = Error) ->
{Error, #{}}.
%%
deduce_activity(#{challenges := Challenges}) ->
Filter = fun(_, Challenge) -> ff_identity_challenge:status(Challenge) == pending end,
case maps:keys(maps:filter(Filter, Challenges)) of
[ChallengeID] ->
{challenge, ChallengeID};
[] ->
undefined
end;
deduce_activity(#{}) ->
undefined.

View File

@ -14,38 +14,39 @@
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
-type contract_template_ref() :: dmsl_domain_thrift:'ContractTemplateRef'().
-type contractor_level() :: dmsl_domain_thrift:'ContractorIdentificationLevel'().
-type id() :: binary().
-type provider() :: #{
id := id(),
payinst_ref := payinst_ref(),
payinst := payinst(),
routes := routes(),
identity_classes := #{
ff_identity_class:id() => ff_identity_class:class()
}
contract_template_ref := contract_template_ref(),
contractor_level := contractor_level()
}.
-type configuration() :: #{
payinst_id := integer(),
contract_template_id := integer(),
contractor_level := contractor_level()
}.
-type payinst() :: dmsl_domain_thrift:'PaymentInstitution'().
-type payinst_ref() :: dmsl_domain_thrift:'PaymentInstitutionRef'().
-type routes() :: [id()].
-type identity_classes() :: #{ff_identity_class:id() => ff_identity_class:class()}.
-export_type([id/0]).
-export_type([provider/0]).
-export_type([routes/0]).
-export_type([identity_classes/0]).
-export([id/1]).
-export([name/1]).
-export([residences/1]).
-export([payinst/1]).
-export([routes/1]).
-export([identity_classes/1]).
-export([contract_template/1]).
-export([contractor_level/1]).
-export([list/0]).
-export([get/1]).
-export([list_identity_classes/1]).
-export([get_identity_class/2]).
%% Pipeline
@ -57,8 +58,8 @@
-spec name(provider()) -> binary().
-spec residences(provider()) -> [ff_residence:id()].
-spec payinst(provider()) -> payinst_ref().
-spec routes(provider()) -> routes().
-spec identity_classes(provider()) -> identity_classes().
-spec contract_template(provider()) -> contract_template_ref().
-spec contractor_level(provider()) -> contractor_level().
id(#{id := ID}) ->
ID.
@ -72,11 +73,11 @@ residences(#{payinst := PI}) ->
payinst(#{payinst_ref := V}) ->
V.
routes(#{routes := V}) ->
V.
contract_template(#{contract_template_ref := Ref}) ->
Ref.
identity_classes(#{identity_classes := ICs}) ->
ICs.
contractor_level(#{contractor_level := Level}) ->
Level.
%%
@ -96,92 +97,49 @@ get(ID) ->
% TODO
% - We need to somehow expose these things in the domain config
% - Possibly inconsistent view of domain config
C = unwrap(get_provider_config(ID)),
PaymentInstitutionRef = #domain_PaymentInstitutionRef{id = maps:get(payment_institution_id, C)},
Routes = maps:get(routes, C),
Config = unwrap(get_config(ID)),
PaymentInstitutionRef = #domain_PaymentInstitutionRef{id = cfg(payment_institution, Config)},
{ok, PaymentInstitution} = ff_domain_config:object({payment_institution, PaymentInstitutionRef}),
IdentityClasses = maps:map(
fun decode_identity_class/2,
maps:get(identity_classes, C)
),
ContractTemplateRef = #domain_ContractTemplateRef{id = cfg(contract_template_id, Config)},
% TODO FF-245: we shouldn't check after provider's configuration will be moved on domain_config
ok = validate_contract_template_ref(ContractTemplateRef),
#{
id => ID,
payinst_ref => PaymentInstitutionRef,
payinst => PaymentInstitution,
identity_classes => IdentityClasses,
routes => Routes
contract_template_ref => ContractTemplateRef,
contractor_level => cfg(contractor_level, Config)
}
end).
-spec list_identity_classes(provider()) -> [ff_identity_class:id()].
list_identity_classes(#{identity_classes := ICs}) ->
maps:keys(ICs).
%% Provider Configuration
-spec get_identity_class(ff_identity_class:id(), provider()) ->
{ok, ff_identity_class:class()}
-spec get_config(id()) ->
{ok, configuration()}
| {error, notfound}.
get_identity_class(IdentityClassID, #{identity_classes := ICs}) ->
ff_map:find(IdentityClassID, ICs).
%%
-spec get_provider_config(id()) ->
%% FIXME: Use propertly defined type
{ok, map()}
| {error, notfound}.
get_provider_config(ID) ->
get_config(ID) ->
case genlib_app:env(fistful, providers, #{}) of
#{ID := Provider} ->
{ok, Provider};
#{ID := ProviderConfig} ->
{ok, #{
payinst_id => maps:get(payment_institution_id, ProviderConfig),
contract_template_id => maps:get(contract_template_id, ProviderConfig),
contractor_level => maps:get(contractor_level, ProviderConfig)
}};
#{} ->
{error, notfound}
end.
cfg(payment_institution, C) ->
maps:get(payinst_id, C);
cfg(contract_template_id, C) ->
maps:get(contract_template_id, C);
cfg(contractor_level, C) ->
maps:get(contractor_level, C).
validate_contract_template_ref(ContractTemplateRef) ->
{ok, _} = ff_domain_config:object({contract_template, ContractTemplateRef}),
ok.
-spec list_providers() -> [id()].
list_providers() ->
maps:keys(genlib_app:env(fistful, providers, #{})).
decode_identity_class(ICID, ICC) ->
Name = maps:get(name, ICC, ICID),
ContractTemplateRef = #domain_ContractTemplateRef{id = maps:get(contract_template_id, ICC)},
{ok, _} = ff_domain_config:object({contract_template, ContractTemplateRef}),
Levels = maps:map(
fun(LID, LC) ->
LName = maps:get(name, LC, LID),
ContractorLevel = maps:get(contractor_level, LC),
% TODO
% - `ok = assert_contractor_level(ContractorLevel)`
#{
id => LID,
name => LName,
contractor_level => ContractorLevel
}
end,
maps:get(levels, ICC)
),
ChallengeClasses = maps:map(
fun(CCID, CCC) ->
CCName = maps:get(name, CCC, CCID),
BaseLevelID = maps:get(base, CCC),
TargetLevelID = maps:get(target, CCC),
{ok, _} = maps:find(BaseLevelID, Levels),
{ok, _} = maps:find(TargetLevelID, Levels),
#{
id => CCID,
name => CCName,
base_level => BaseLevelID,
target_level => TargetLevelID
}
end,
maps:get(challenges, ICC, #{})
),
InitialLevelID = maps:get(initial_level, ICC),
{ok, _} = maps:find(InitialLevelID, Levels),
#{
id => ICID,
name => Name,
contract_template_ref => ContractTemplateRef,
initial_level => InitialLevelID,
levels => Levels,
challenge_classes => ChallengeClasses
}.

View File

@ -9,7 +9,6 @@
-export([get_missing_fails/1]).
-export([create_missing_fails/1]).
-export([create_ok/1]).
-export([identify_ok/1]).
%%
@ -25,14 +24,12 @@ all() ->
[
get_missing_fails,
create_missing_fails,
create_ok,
identify_ok
create_ok
].
-spec get_missing_fails(config()) -> test_return().
-spec create_missing_fails(config()) -> test_return().
-spec create_ok(config()) -> test_return().
-spec identify_ok(config()) -> test_return().
-spec init_per_suite(config()) -> config().
@ -77,18 +74,7 @@ create_missing_fails(C) ->
id => ID,
name => Name,
party => Party,
provider => <<"who">>,
class => <<"person">>
},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
{error, {identity_class, notfound}} = ff_identity_machine:create(
#{
id => ID,
name => Name,
party => Party,
provider => <<"good-one">>,
class => <<"nosrep">>
provider => <<"who">>
},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
).
@ -102,68 +88,14 @@ create_ok(C) ->
id => ID,
name => Name,
party => Party,
provider => <<"good-one">>,
class => <<"person">>
provider => <<"good-one">>
},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
I1 = ff_identity_machine:identity(unwrap(ff_identity_machine:get(ID))),
{ok, accessible} = ff_identity:is_accessible(I1),
Party = ff_identity:party(I1),
Party = ff_identity:party(I1).
identify_ok(C) ->
ID = genlib:unique(),
Party = create_party(C),
Name = <<"Identity Name">>,
ok = ff_identity_machine:create(
#{
id => ID,
name => Name,
party => Party,
provider => <<"good-one">>,
class => <<"person">>
},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ICID = genlib:unique(),
{ok, S1} = ff_identity_machine:get(ID),
I1 = ff_identity_machine:identity(S1),
{error, notfound} = ff_identity:challenge(ICID, I1),
D1 = ct_identdocstore:rus_retiree_insurance_cert(genlib:unique(), C),
D2 = ct_identdocstore:rus_domestic_passport(C),
ChallengeParams = #{
id => ICID,
class => <<"sword-initiation">>
},
{error, {challenge, {proof, insufficient}}} = ff_identity_machine:start_challenge(
ID,
ChallengeParams#{proofs => []}
),
{error, {challenge, {proof, insufficient}}} = ff_identity_machine:start_challenge(
ID,
ChallengeParams#{proofs => [D1]}
),
ok = ff_identity_machine:start_challenge(
ID,
ChallengeParams#{proofs => [D1, D2]}
),
{error, {challenge, {pending, ICID}}} = ff_identity_machine:start_challenge(
ID,
ChallengeParams#{proofs => [D1, D2]}
),
{completed, _} = ct_helper:await(
{completed, #{resolution => approved}},
fun() ->
{ok, S} = ff_identity_machine:get(ID),
{ok, IC} = ff_identity:challenge(ICID, ff_identity_machine:identity(S)),
ff_identity_challenge:status(IC)
end
),
{ok, S3} = ff_identity_machine:get(ID),
I3 = ff_identity_machine:identity(S3),
{ok, ICID} = ff_identity:effective_challenge(I3).
create_party(_C) ->
ID = genlib:bsuuid(),
_ = ff_party:create(ID),

View File

@ -167,9 +167,9 @@ create_party(_C) ->
ID.
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, <<"person">>, C).
create_identity(Party, <<"good-one">>, C).
create_identity(Party, ProviderID, ClassID, _C) ->
create_identity(Party, ProviderID, _C) ->
ID = genlib:unique(),
Name = <<"Identity Name">>,
ok = ff_identity_machine:create(
@ -177,8 +177,7 @@ create_identity(Party, ProviderID, ClassID, _C) ->
id => ID,
name => Name,
party => Party,
provider => ProviderID,
class => ClassID
provider => ProviderID
},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),

View File

@ -308,7 +308,7 @@ consume_eventsinks(_) ->
prepare_standard_environment({_Amount, Currency} = Cash, C) ->
PartyID = create_party(C),
IdentityID = create_person_identity(PartyID, C),
IdentityID = create_identity(PartyID, C),
WalletFromID = create_wallet(IdentityID, <<"My wallet from">>, <<"RUB">>, C),
ok = await_wallet_balance({0, Currency}, WalletFromID),
WalletToID = create_wallet(IdentityID, <<"My wallet to">>, <<"RUB">>, C),
@ -395,19 +395,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -261,7 +261,7 @@ unknown_test(_C) ->
prepare_standard_environment(Currency, C) ->
PartyID = create_party(C),
IdentityID = create_person_identity(PartyID, C),
IdentityID = create_identity(PartyID, C),
WalletFromID = create_wallet(IdentityID, <<"My wallet from">>, <<"RUB">>, C),
ok = await_wallet_balance({0, Currency}, WalletFromID),
WalletToID = create_wallet(IdentityID, <<"My wallet to">>, <<"RUB">>, C),
@ -303,19 +303,16 @@ create_party(_C) ->
_ = ff_party:create(ID),
ID.
create_person_identity(Party, C) ->
create_person_identity(Party, C, <<"good-one">>).
create_identity(Party, C) ->
create_identity(Party, <<"good-one">>, C).
create_person_identity(Party, C, ProviderID) ->
create_identity(Party, ProviderID, <<"person">>, C).
create_identity(Party, ProviderID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, C).
create_identity(Party, ProviderID, ClassID, C) ->
create_identity(Party, <<"Identity Name">>, ProviderID, ClassID, C).
create_identity(Party, Name, ProviderID, ClassID, _C) ->
create_identity(Party, Name, ProviderID, _C) ->
ID = genlib:unique(),
ok = ff_identity_machine:create(
#{id => ID, name => Name, party => Party, provider => ProviderID, class => ClassID},
#{id => ID, name => Name, party => Party, provider => ProviderID},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
),
ID.

View File

@ -60,38 +60,16 @@
]},
{fistful, [
{providers, #{
{provider, #{
<<"ncoeps">> => #{
payment_institution_id => 100,
routes => [<<"mocketbank">>],
identity_classes => #{
<<"person">> => #{
name => <<"Person">>,
contract_template_id => 10000,
initial_level => <<"anonymous">>,
levels => #{
<<"anonymous">> => #{
name => <<"Anonymous">>,
contractor_level => none
},
<<"partly-identified">> => #{
name => <<"Partially identified">>,
contractor_level => partial
},
<<"identified">> => #{
name => <<"Fully identified">>,
contractor_level => full
}
},
challenges => #{
<<"esia">> => #{
name => <<"ЕСИА">>,
base => <<"anonymous">>,
target => <<"partly-identified">>
}
}
}
}
contract_template_id => 10000,
contractor_level => full
},
<<"test">> => #{
payment_institution_id => 1,
contract_template_id => 1,
contractor_level => full
}
}},
{services, #{

View File

@ -30,7 +30,7 @@
0},
{<<"fistful_proto">>,
{git,"https://github.com/rbkmoney/fistful-proto.git",
{ref,"914c9986d45635f93569d896f515a0b3e93ea913"}},
{ref,"519551dba6aa3618e879f0f81244ff3208d67edd"}},
0},
{<<"genlib">>,
{git,"https://github.com/rbkmoney/genlib.git",