// Execute the mutulChallengeResponse server: in this example the ocra suite is predefined both for the client and the server
// 1. Wait for the client's randomly generated question
// 2. Send to the client both the calculated ocra value (based on the ocra suite and client's + server's questions) and the server's question
// 3. Get from the client the calculated ocra value based on the client's and server's questions
// 4. Calculate the expected ocra value based on both the client's and the server's questions
// 5. Comapre the calculated ocra value with the one recived from the client
// 6. If the values are equal: the client is authenticated
//    6.1. Send an OK message to the client
//    6.2. Increase the 'ocra used' counter (to prevent replay attacks)
// 7. Else (the values are not equal) send a NOK message to the client
func mutualChallengeResponseServer(key string, counter string) {
	QS := "Server 9879"

	QC := <-channel

	RS, err := ocra.GenerateOCRAAdvance(mutualOcraSuite, key, counter, QC+QS, mutualPassword, "", "")
	if err != nil {
		doneChannel <- fmt.Sprintf(failFmt, err)
	}

	channel <- RS
	channel <- QS

	RC := <-channel
	cOtp, err := ocra.GenerateOCRAAdvance(mutualOcraSuite, key, counter, QS+QC, mutualPassword, "", "")
	if err != nil {
		doneChannel <- fmt.Sprintf(failFmt, err)
	}

	if RC == cOtp {
		channel <- OKStr
		val, _ := strconv.Atoi(counter)
		counter = fmt.Sprintf("%06d", val+1)
	} else {
		channel <- NOKStr
	}
}
func mutualChallengeResponseClient(key string, counter string) {
	QC := "Client 1234"
	channel <- QC

	RS := <-channel
	QS := <-channel

	sOtp, err := ocra.GenerateOCRAAdvance(mutualOcraSuite, key, counter, QC+QS, mutualPassword, "", "")
	if err != nil {
		doneChannel <- fmt.Sprintf(failFmt, err)
	}

	RC, err := ocra.GenerateOCRAAdvance(mutualOcraSuite, key, counter, QS+QC, mutualPassword, "", "")
	if err != nil {
		doneChannel <- fmt.Sprintf(failFmt, err)
	}

	if RS == sOtp {
		channel <- RC
	} else {
		channel <- "0"
	}
	fmt.Printf("Client/Server otp: (%v,%v), Ocra suite: %v, Client/Server questions: ('%v','%v'), counter: %v, password: %v\n",
		RC, RS, mutualOcraSuite, QC, QS, counter, mutualPassword)
	ok := <-channel
	if ok == OKStr {
		val, _ := strconv.Atoi(counter)
		counter = fmt.Sprintf("%06d", val+1)
	}
	doneChannel <- ok
}
func TestOneWayChallengeResponse(t *testing.T) {
	userName := usersName[0]

	initAListOfUsers(t, usersName)

	url := listener + servicePath + fmt.Sprintf(cr.ConvertCommandToRequest(urlCommands[verifyUserIdentityCommand]), usersPath, userName, verifyUserIdentityChallengeToken)
	res := exeCommandCheckRes(t, cr.HTTPGetStr, url, http.StatusOK, "", cr.StringMessage{Str: cr.GetMessageStr})
	var OcraData ocraData
	err := json.Unmarshal([]byte(res), &OcraData)
	if err != nil {
		t.Errorf("Test fail: execute GET to '%v' expected to get ocra data but received: %v, error: %v",
			url, res, err)
	}
	//Calculate the cleint OTP
	otp, err := ocra.GenerateOCRAAdvance(ocraUserDataInfo.OcraSuite, secretCode,
		OcraData.Counter, OcraData.ServerQuestion, OcraData.Password, OcraData.SessionID, OcraData.TimeStamp)
	logger.Info.Println("The calculated OTP for ocra data:", res, "is:", otp)
	if err != nil {
		t.Errorf("Test fail: Try to generate OCRA with the following parameters: %v, error: %v", res, err)
	}
	OcraData.Otp = otp
	data, _ := json.Marshal(OcraData)
	url = listener + servicePath + fmt.Sprintf(cr.ConvertCommandToRequest(urlCommands[verifyUserIdentityCommand]), usersPath, userName, verifyUserIdentityOtpToken)
	exeCommandCheckRes(t, cr.HTTPPutStr, url, http.StatusOK, string(data), cr.Match{Match: true, Message: ""})
}
// Execute the oneWayChallengeResponse client:
// 1. Wait for the ocra suite defined by the server (in this example)
//    and the server's randomly generated question
// 2. Send to the server the calculated ocra value (using the ocra suite and the server's question)
// 3. Send the server's approval to the "done channel"
func oneWayChallengeResponseClient(key string) {
	oneWayOcraSuite := <-channel
	question := <-channel

	otp, err := ocra.GenerateOCRAAdvance(oneWayOcraSuite, key, "", question, "", "", "")
	if err != nil {
		doneChannel <- fmt.Sprintf(failFmt, err)
	}
	fmt.Printf("Client otp: %v, Ocra suite: %v, Question: '%v'\n", otp, oneWayOcraSuite, question)
	channel <- otp
	ok := <-channel
	doneChannel <- ok
}
func TestMutualChallengeResponse(t *testing.T) {
	var OcraData ocraData
	userName := usersName[0]

	initAListOfUsers(t, usersName)

	OcraData.ClientQuestion = "The client 1"
	url := listener + servicePath + fmt.Sprintf(cr.ConvertCommandToRequest(urlCommands[verifyUserIdentityCommand]), usersPath, userName, verifyUserIdentityMutualChallengeStep1Token)
	data, _ := json.Marshal(cr.StringMessage{Str: OcraData.ClientQuestion})
	res := exeCommandCheckRes(t, cr.HTTPPutStr, url, http.StatusOK, string(data), cr.StringMessage{Str: cr.GetMessageStr})
	err := json.Unmarshal([]byte(res), &OcraData)
	if err != nil {
		t.Errorf("Test fail: execute GET to '%v' expected to get ocra data but received: %v, error: %v",
			url, res, err)
		t.FailNow()
	}
	clientOtp, err := ocra.GenerateOCRAAdvance(ocraUserDataInfo.OcraSuite, secretCode,
		OcraData.Counter, OcraData.ServerQuestion+OcraData.ClientQuestion, OcraData.Password, OcraData.SessionID, OcraData.TimeStamp)
	serverOtp, _ := ocra.GenerateOCRAAdvance(ocraUserDataInfo.OcraSuite, secretCode,
		OcraData.Counter, OcraData.ClientQuestion+OcraData.ServerQuestion, OcraData.Password, OcraData.SessionID, OcraData.TimeStamp)
	logger.Info.Println("The calculated client OTP for ocra data:", res, "and client question:", OcraData.ClientQuestion, "is:", clientOtp, "the server otp:", serverOtp)
	if err != nil {
		t.Errorf("Test fail: Try to generate OCRA with the following parameters: %v, error: %v", res, err)
		t.FailNow()
	}

	if OcraData.Otp != serverOtp {
		t.Errorf("Test fail: The calculated server OTP: %v is not as the received OTP: %v", serverOtp, OcraData.Otp)
		t.FailNow()
	}

	url = listener + servicePath + fmt.Sprintf(cr.ConvertCommandToRequest(urlCommands[verifyUserIdentityCommand]), usersPath, userName, verifyUserIdentityMutualChallengeStep2Token)
	OcraData.Otp = clientOtp
	data, _ = json.Marshal(OcraData)
	exeCommandCheckRes(t, cr.HTTPPutStr, url, http.StatusOK, string(data), cr.Match{Match: true, Message: ""})
}
// In this example, The oneWayOcraSuite is defined by the server and sent to the client
// 1. Send the ocra suite and the "random" question to the client
// 2. Comapre the expected calculated ocra value with the one recived from the client
// 3. Based on the result of the comparison, send either an 'OK' or a 'NOK' message to the client
func oneWayChallengeResponseServer(key string) {
	oneWayOcraSuite := "OCRA-1:HOTP-SHA1-6:QA08"
	question := "abcd1234"

	channel <- oneWayOcraSuite
	channel <- question

	refOtp, err := ocra.GenerateOCRAAdvance(oneWayOcraSuite, key, "", question, "", "", "")
	if err != nil {
		doneChannel <- fmt.Sprintf(failFmt, err)
	}
	otp := <-channel
	if otp == refOtp {
		channel <- OKStr
	} else {
		channel <- NOKStr
	}
}
func (o OcraRestful) restVerifyOcraUserIdentityMutualChallengeStep2(request *restful.Request, response *restful.Response) {
	data := o.getOcra(request, response)
	if data == nil {
		return
	}
	var ocraData ocraData
	err := request.ReadEntity(&ocraData)
	clientOtp, err := ocra.GenerateOCRAAdvance(data.OcraSuite, string(data.Key),
		ocraData.Counter, ocraData.ServerQuestion+ocraData.ClientQuestion, ocraData.Password, ocraData.SessionID, ocraData.TimeStamp)
	logger.Trace.Println("ocraData:", ocraData, "client otp:", ocraData.Otp, "calculated client otp:", clientOtp)
	if ocraData.Otp == clientOtp && err == nil {
		response.WriteHeaderAndEntity(http.StatusOK, cr.Match{Match: true, Message: "OTP match"})
		logger.Trace.Println("Server verify the OTP successfully")
	} else {
		logger.Trace.Println("Server calculated OTP:", clientOtp, "is different from the one sent from the client", ocraData.Otp)
		response.WriteHeaderAndEntity(http.StatusOK, cr.Match{Match: false, Message: "Client OTP doesn't match"})
	}
}
func (o OcraRestful) restVerifyOcraUserIdentityMutualChallengeStep1(request *restful.Request, response *restful.Response) {
	data := o.getOcra(request, response)
	if data == nil {
		return
	}
	var ocraData ocraData
	err := request.ReadEntity(&ocraData)
	logger.Trace.Println("Server received data:", ocraData, "Error:", err)
	ocraData.ServerQuestion = o.getRandString(ocraQuestionLen)
	serverOtp, err := ocra.GenerateOCRAAdvance(data.OcraSuite, string(data.Key),
		ocraData.Counter, ocraData.ClientQuestion+ocraData.ServerQuestion, ocraData.Password, ocraData.SessionID, ocraData.TimeStamp)
	if err != nil {
		o.setError(response, http.StatusNotFound, err)
		return
	}
	logger.Trace.Println("ocraData:", ocraData, "server otp:", serverOtp)
	ocraData.Otp = serverOtp
	response.WriteHeaderAndEntity(http.StatusOK, ocraData)
}
func (o OcraRestful) restVerifyOcraUserIdentityCheckOtp(request *restful.Request, response *restful.Response) {
	data := o.getOcra(request, response)
	if data == nil {
		return
	}
	var ocraData ocraData
	err := request.ReadEntity(&ocraData)
	if err != nil {
		str := fmt.Sprintf("Error while reading data '%v', error: %v", ocraData, err)
		o.setError(response, http.StatusNotFound, fmt.Errorf(str))
		return
	}
	// verify client OTP
	otp, err := ocra.GenerateOCRAAdvance(data.OcraSuite, string(data.Key), ocraData.Counter,
		ocraData.ServerQuestion, ocraData.Password, ocraData.SessionID, ocraData.TimeStamp)
	logger.Trace.Println("ocraData:", ocraData, "otp:", otp, "client otp:", ocraData.Otp)
	if ocraData.Otp == otp && err == nil {
		response.WriteHeaderAndEntity(http.StatusOK, cr.Match{Match: true, Message: "OTP match"})
		logger.Trace.Println("Server verify the OTP successfully")
	} else {
		logger.Trace.Println("Server calculated OTP:", otp, "is different from the one sent from the client", ocraData.Otp)
		response.WriteHeaderAndEntity(http.StatusOK, cr.Match{Match: false, Message: "OTP doesn't match"})
	}
}