Why cyrsasl_scram mechanism is not allowing base64 GUID? - erlang

I am writing a chat communication app.
If the user's unique id is given in Base 64 GUID format, it is throwing bad_username error.
In this file: https://pow.gs/mirror/ejabberd/-/blob/fd8e07af4789be362a61755ea47f216baeb64989/src/cyrsasl_scram.erl, there is a method to remove the == from username:
unescape_username(<<"">>) -> <<"">>;
unescape_username(EscapedUsername) ->
Pos = str:str(EscapedUsername, <<"=">>),
if Pos == 0 -> EscapedUsername;
true ->
Start = str:substr(EscapedUsername, 1, Pos - 1),
End = str:substr(EscapedUsername, Pos),
EndLen = byte_size(End),
if EndLen < 3 -> error;
true ->
case str:substr(End, 1, 3) of
<<"=2C">> ->
<<Start/binary, ",",
(unescape_username(str:substr(End, 4)))/binary>>;
<<"=3D">> ->
<<Start/binary, "=",
(unescape_username(str:substr(End, 4)))/binary>>;
_Else -> error
end
end
end.
I don't know why this has been written. If I remove this particular code, the connection is working fine. Please let me know why it is restricted.

If the users' unique id is given in Base 64 GUID format, it is throwing bad_username error.
Right:
call xmpp_sasl_scram:unescape_username(<<"user1">>)
returned from xmpp_sasl_scram:unescape_username/1 -> <<"user1">>
call xmpp_sasl_scram:unescape_username(<<"user3==ABC">>)
returned from xmpp_sasl_scram:unescape_username/1 -> error
call xmpp_sasl_scram:unescape_username(<<"user4=DEF">>)
returned from xmpp_sasl_scram:unescape_username/1 -> error
call xmpp_sasl_scram:unescape_username(<<"user5=">>)
returned from xmpp_sasl_scram:unescape_username/1 -> error
I don't know why this has been written. If I remove this particular code, the connection is working fine. Please let me know why it is restricted.
I don't know, either. But that code exists since nine years ago:
https://github.com/processone/ejabberd/commit/e80b92b48148505b44c6a378db36badfe60fce79#diff-5c51943c1268ffe26fe3b041b20675c6R136
Whatever reason there is for it, it's obviously a good reason.

Related

Login in a multi-page website (SAFE Stack)

Does anybody use the Elmish routing for a multi-page app (SAFE Stack in my case) as specified by Maxime Mangel here on StackOverflow , but with a login page?
Do you, at the same time, use the accessibility (Anonymous/LoggedIn) philosophy as specified here in the Elmish Book?
If so, you probably use different coding than in the Elmish Book (as I do), but in any case you probably need to have login results available in the main page (Main.fs) to implement the accessibility logic. The Elmish Book uses (in Login.fs) a function with an active pattern let (|UserLoggedIn|_|) = ... and this function is called from the main or home page (see here).
But it wouldn't work in my app.
So my question is:
How do you transfer login results from the login page (Login.fs) into the main page (Main.fs)?
You can easily spot my login results here in the code:
Login.fs //client
let update (msg: Msg) (model: Model) : Model * Cmd<Msg> =
match msg with
| SetUsrInput value -> { model with InputUsr = value }, Cmd.none
| SetPswInput value -> { model with InputPsw = value }, Cmd.none
| SendUsrPswToServer ->
let buttonClickEvent = SharedLoginValues.create model.InputUsr model.InputPsw
let cmd = Cmd.OfAsync.perform getLoginApi.login buttonClickEvent GetLoginResults
model, cmd
| GetLoginResults value ->
let result =
match value with
| SharedApi.UsernameOrPasswordIncorrect -> { model with User = ApplicationUser.Anonymous}
| SharedApi.LoggedIn user -> { model with User = ApplicationUser.LoggedIn user}
result, Cmd.ofMsg AskServerForSecurityTokenFile
Meanwhile, I use a workaround with reaching login results that I save on the server. Although the accesibility logic works as expected, the workaround seems to be cumbersome - I already have the login results in the login page so why reaching them twice...
Here, it is my code for the accesibility logic in Main.fs that should use the login results. By the way, the code is, to my big surprise, much simpler than that in the Elmish Book.
Main.fs //client
let private setRoute (optRoute: RouterM.Route option) model =
let model =
let applicationUser =
//model.GetSecurityTokenFile -> this is the workaround
// - results from the login page should be matched here instead
match model.GetSecurityTokenFile with
| true -> LoggedIn model.user
| false -> Anonymous
let currentRoute =
//model.GetSecurityTokenFile -> this is the workaround
// - results from the login page should be matched here instead
match model.GetSecurityTokenFile with
| true -> optRoute
| false -> Some RouterM.Route.Home //or to a login page
{
model with CurrentRoute = currentRoute
User = applicationUser
}
Well, just 2x match and that's really all. Or have I missed anything here?
match optRoute with
//...some code
| Some (RouterM.Route.CMSRozcestnik cmsRozcestnikId) ->
match model.User with
| Anonymous ->
let (homeModel, homeCmd) = Home.init () //or Login.init
{ model with ActivePage = Page.Home homeModel }, cmd2 HomeMsg homeCmd AskServerForDeletingSecurityTokenFile
| LoggedIn user ->
let (cmsRozcestnikModel, cmsRozcestnikCmd) = CMSRozcestnik.init cmsRozcestnikId
{ model with ActivePage = Page.CMSRozcestnik cmsRozcestnikModel }, Cmd.map CMSRozcestnikMsg cmsRozcestnikCmd
| _ -> let (homeModel, homeCmd) = Home.init () //or Login.init
{ model with ActivePage = Page.Home homeModel }, cmd2 HomeMsg homeCmd AskServerForDeletingSecurityTokenFile
If needed, the entire code is here on GitHub:
https://github.com/MiroslavHustak/SAFE-Stack-simple-multipage-website-with-CMS-
I have received an answer to my question from Maxime Mangel via F# Slack.
Look at the section "Make the child communicate with the parent" in the link below and pay attention to the message ExternalMsg. Then just implement the code into your system. It worked with my code. If interested, you can look at the code on GitHub (the link is in the question).
https://medium.com/#MangelMaxime/my-tips-for-working-with-elmish-ab8d193d52fd

Cant load real-time data from tws

I can't get real-time tick with API for GBP.CHF#IDEALPRO/ My log:
0:53:36:282 <- 9-8-1073741829-0-GBP-CASH--0-----CHF---0---
10:53:36:282 <- 1-11-1073741830-0-GBP-CASH--0-----CHF---0-233,236,258-0-0--
10:53:36:282 -> ---R4-2-1073741830-321-Error validating request.-'bX' : cause - Please enter exchange-
10:53:36:283 <- 1-11--1073741830-0-GBP-CASH--0-----CHF---0--1-0--
10:53:36:283 -> ---S4-2--1073741830-321-Error validating request.-'bX' : cause - Please enter exchange-
10:53:36:318 <- 9-8-1073741831-0-GBP-CASH--0-----CHF---0---
Nothing incoming from tws. Please help.
Here's your log compared to my log.
1-11-1073741830-0-GBP-CASH--0 --- --CHF---0-233,236,258-0-0--
1-11-1 -0-GBP-CASH--0.0---IDEALPRO--CHF---0-233-0-0--
You just forgot the exchange.
contract = Contract()
contract.symbol = "GBP"
contract.secType = "CASH"
contract.exchange = "IDEALPRO"
contract.currency = "CHF"
app.reqMktData(1, contract, "233", False, False, None)
I'm not sure about your generic tick list, not all type are available for forex. I just threw in 233 to see if it would cause an error but it worked.

unexpected end of input in return in neo4j

I am trying to create a graph relationship using neo4j
First I have created
create (populate_stock_summary:Dag{uuid: "c4ca4238-a0b9-3382-8dcc-509a6f75849b", version: "1760270902"}),
(map_stock_summary:map{uuid: "d41d8cd9-8f00-3204-a980-0998ecf8427e",version : "1466522157"}),
(stock_summary_filter :filter{uuid: "6fe5451a-4ed3-11e6-beb8-9e71128cae77" ,version : "1460270889"}),
(rel_00003:relation{uuid: "f33490a0-133d-11e6-a837-0800200c9a66", version : "1466003152"}),
(stock_summary_datapod:datapod{uuid: "e3fed0a4-4aca-11e6-beb8-9e71128cae77", version : "1160270897"}),
(max_lastSale_formula :formula{uuid: "096dac4b-fee8-11e5-86aa-5e5517507c66",version : "1460270899"}),
(populate_stock_summary_group:group{uuid: "16fbf5bd-8173-4bff-8b97-1b04e3057475", verssion : "1660270892"}),
(stock_list:Stock_list_datapod{uuid: "60878178-fee7-11e5-86aa-5e5517507c66", version : "1460270897"})
and all nodes are created successfully.
Next I am trying to build a relationship among them. I executed following.
Match (populate_stock_summary:Dag),
(map_stock_summary:Map),
(stock_summary_filter :filter),
(populate_stock_summary_group:group),
(rel_00003:relation),
(max_lastSale_formula:formula),
(stock_list:stock_list_datapod),
(stock_summary_datapod:datapod)
where populate_stock_summary.uuid = "c4ca4238-a0b9-3382-8dcc-509a6f75849b"
and map_stock_summary.uuid = "d41d8cd9-8f00-3204-a980-0998ecf8427e"
and stock_summary_filter.uuid ="6fe5451a-4ed3-11e6-beb8-9e71128cae77"
and populate_stock_summary_group.uuid ="16fbf5bd-8173-4bff-8b97-1b04e3057475"
and rel_00003.uuid = "f33490a0-133d-11e6-a837-0800200c9a66"
and max_lastSale_formula.uuid = "096dac4b-fee8-11e5-86aa-5e5517507c66"
and stock_list.uuid ="60878178-fee7-11e5-86aa-5e5517507c66"
and stock_summary_datapod.uuid ="e3fed0a4-4aca-11e6-beb8-9e71128cae77"
create (populate_stock_summary)-[ref1:refers_to{Desc : "Refering_to_map"}]->(map_stock_summary),
(populate_stock_summary) -[ref2:refers_to{Desc :"Refering_to_filter}] -> (stock_summary_filter),
(map_stock_summary) -[ref3:source_depends_on]->(rel_00003),
(map_stock_summary)-[ref4:target_depends_on]->(stock_summary_datapod),
(map_stock_summary) -[ref5:refers_to]-> (max_lastSale_formula),
(map_stock_summary) -[ref6:has_groupBy_property] -> (populate_stock_summary_group),
(populate_stock_summary_group) -[ref7:depends_on] -> (rel_00003),
(stock_summary_filter) -[ref8:depends_on] -> (rel_00003),
(rel_00003) - [ref9:depends_on] -> (stock_list)
return ref1,ref2,ref3,ref4,ref5,ref6,ref7,ref8,ref9
And here I am getting
Unexpected end of input: expected '\', ANY or '"' (line 21, column 52 (offset: 1498))
"return ref1,ref2,ref3,ref4,ref5,ref6,ref7,ref8,ref9
What went wrong here?
Thanks in advance.
You are missing a closing quote in the string "Refering_to_filter.

erlang google oauth2 protocol for google calling apis

Hello I am writing oauth 2 library to access google api's and my code is as follows
jwt_create() ->
{ok,PemBin} = file:read_file("your-key-file.pem"),
PemEntry = public_key:pem_decode(PemBin),
[A,B] = PemEntry,
io:format("A:: ~p ~n",[A]),
PrivateKey = public_key:pem_entry_decode(PemEntry),
JwtHeaderJson = encode_json(jwt_header()),
JwtClaimsetJson = encode_json(jwt_claimset()),
ComputeSignature = compute_signature(JwtHeaderJson, JwtClaimsetJson, PrivateKey),
Z=binary:replace(
binary:replace(<<JwtHeaderJson/binary, ".", JwtClaimsetJson/binary, ".", ComputeSignature/binary>>,
<<"+">>, <<"-">>, [global]),
<<"/">>, <<"_">>, [global]),
io:format("JWT:: ~p ~n",[Z]).
compute_signature(Header, ClaimSet,#'RSAPrivateKey'{publicExponent=Exponent
,modulus=Modulus
,privateExponent=PrivateExponent}) ->
base64:encode(crypto:sign(rsa, sha256, <<Header/binary, ".", ClaimSet/binary>>,
[Exponent, Modulus, PrivateExponent])).
encode_json(JWToken) ->
base64:encode(jsx:encode(JWToken)).
I am getting error as follows:
exception error: no function clause matching
public_key:pem_entry_decode([{'PrivateKeyInfo',<<48,130,4,191,2,1,0,48,13,6,9,42,134,
72,134,247,13,1,1,1,5,0,4,130,4,...>>,
not_encrypted},
{'Certificate',<<48,130,3,96,48,130,2,72,160,3,2,1,2,2,8,
79,59,244,35,60,15,3,155,48,...>>,
not_encrypted}]) (public_key.erl, line 123)
in function googleoauth:jwt_create/0 (src/googleoauth.erl, line 55)
Please help me in generating JWS and JWT for OAUTH 2 for accessing google apis
You are passing the wrong thing to public_key:pem_entry_decode/1:
This will resolve your problem:
PrivateKey = public_key:pem_entry_decode(A),
public_key:pem_entry_decode/1 takes a single pem_entry() but a PEM file can contain many entries, perhaps your code PemEntry = public_key:pem_decode(PemBin) should read PemEntries = public_key:pem_decode(PemBin) instead?
Also note the line before assumes 2 list entries, you might have meant this instead (not sure your intent here though)?
[A|B] = PemEntry,

how to use mnesia:select/4 and mnesia:select/1 for paging query

a table named "md" with structure {id,name},I want read records from md use paging query,I tried mnesia:select/4 and mnesia:select/1 as below:
%% first use select/2: "ID < 10",returned [1,2,4,3,8,5,9,7,6]
(ejabberd#localhost)5> mnesia:activity(transaction,fun mnesia:select/2,md, [{{md,'$1','_'},[{'<','$1',10}],['$1']}]).
{atomic,[1,2,4,3,8,5,9,7,6]}
%%but when query with select/4,returned [6], why?
(ejabberd#localhost)7> {atomic,{R1,C1}}=mnesia:activity(transaction,fun mnesia:select/4,md,[{{md,'$1','_'},[{'<','$1',10}],['$1']}],5,read).
{atomic,{[6],
{mnesia_select,md,
{tid,10535470,<0.460.0>},
ejabberd#localhost,disc_only_copies,
{dets_cont,select,5,
<<0,0,0,29,18,52,86,120,0,0,0,21,131,104,3,...>>,
{141720,148792,<<>>},
md,<0.130.0>,<<>>},
[],undefined,undefined,
[{{md,'$1','_'},[{'<','$1',10}],['$1']}]}}}
%% and then use mnesia:select/1 with continuation "C1",got wrong_transaction
(ejabberd#localhost)8> mnesia:activity(transaction,fun mnesia:select/1,C1).
{aborted,wrong_transaction}
how to use mnesia:select/4 and mnesia:select/1 for paging query?
You will have to call select/1 inside the same transaction.
Otherwise the table can change between invocations to select/4 and select/1.
You must use a dirty context if you want to use is as written above.
here is my solution:
use async_dirty instead of transaction
{Record,Cont}=mnesia:activity(async_dirty, fun mnesia:select/4,[md,[{Match_head,[Guard],[Result]}],Limit,read])
then read next Limit number of records:
mnesia:activity(async_dirty, fun mnesia:select/1,[Cont])
full code:
-record(md,{id,name}).
batch_delete(Id,Limit) ->
Match_head = #md{id='$1',name='$2'},
Guard = {'<','$1',Id},
Result = '$_',
{Record,Cont} = mnesia:activity(async_dirty, fun mnesia:select/4,[md,[{Match_head,[Guard],[Result]}],Limit,read]),
delete_next({Record,Cont}).
delete_next('$end_of_table') ->
over;
delete_next({Record,Cont}) ->
delete(Record),
delete_next(mnesia:activity(async_dirty, fun mnesia:select/1,[Cont])).
delete(Records) ->
io:format("delete(~p)~n",[Records]),
F = fun() ->
[ mnesia:delete_object(O) || O <- Records]
end,
mnesia:transaction(F).

Resources