public async Task <IActionResult> ContentHit([FromHeader] string authorization, [FromBody] JObject request) { var tokenModel = TokenConvert.DeserializeEncryptedToken <WebhookTokenModel>(authorization, _config.GetValue <string>("EncodingKey") ?? "whoops"); var recordProvider = new QuickBaseRecordProvider(new HttpClient(), tokenModel.QuickBaseRealm, tokenModel.QuickBaseToken); var requestModel = new UpdateRecordRequest { To = tokenModel.QuickBaseRequestTableId, Data = new List <Dictionary <string, RecordValue> > { new Dictionary <string, RecordValue> { { tokenModel.QuickBaseRequestTableMatrix["applicationId"], new RecordValue(request["data"]["originalRequest"]["applicationId"].Value <string>()) }, { tokenModel.QuickBaseRequestTableMatrix["requestDate"], new RecordValue(request["data"]["eventDate"].Value <string>()) }, { tokenModel.QuickBaseRequestTableMatrix["platform"], new RecordValue(request["data"]["originalRequest"]["assistant"].Value <string>()) }, { tokenModel.QuickBaseRequestTableMatrix["requestId"], new RecordValue(request["data"]["originalRequest"]["requestId"]?.Value <string>() ?? Guid.NewGuid().ToString()) }, { tokenModel.QuickBaseRequestTableMatrix["userId"], new RecordValue(request["data"]["originalRequest"]["userId"].Value <string>()) }, { tokenModel.QuickBaseRequestTableMatrix["sessionId"], new RecordValue(request["data"]["originalRequest"]["sessionId"].Value <string>()) }, { tokenModel.QuickBaseRequestTableMatrix["slots"], new RecordValue(request["data"]["originalRequest"]["slots"].ToString()) }, { tokenModel.QuickBaseRequestTableMatrix["contentItemId"], new RecordValue(request["data"]["content"]["id"].Value <string>()) }, { tokenModel.QuickBaseRequestTableMatrix["featureTypeId"], new RecordValue(request["data"]["featureTypeId"].Value <string>()) } } } }; var result = await recordProvider.AddOrUpdateRecord(requestModel); if (result?.ResultType == ServiceResult.ResultType.Ok) { return(Ok(result.Data)); } return(BadRequest(result.Errors)); }
public async Task <CapabilitiesResponse> GetAsync(CapabilitiesRequestArgs args, CancellationToken token) { try { var requestArgs = new TokenSendRequestArgs(args.RequestUri, accessToken: args.AccessToken); var response = await _client.SendRequestAsync(requestArgs, token); var assertionModel = _jwtTokenParser.Parse(response); var validationArgs = CreateValidationArgs(args, assertionModel); if (!await _tokenResponseValidator.IsValidAsync(validationArgs, args.SchemeOwnerAccessToken, token)) { throw new UnsuccessfulResponseException($"Token which was retrieved from {args.RequestUri} is corrupted."); } return(TokenConvert.DeserializeClaim <CapabilitiesResponse>( assertionModel.JwtSecurityToken, "capabilities_info")); } catch (UnsuccessfulResponseException) { throw; } catch (Exception e) { throw new UnsuccessfulResponseException("Capabilities request was unsuccessful.", e); } }
public async Task <IReadOnlyCollection <CertificateAuthority> > GetAsync(string accessToken, CancellationToken token) { try { var requestArgs = new TokenSendRequestArgs(_requestUri, accessToken: accessToken); var response = await _client.SendRequestAsync(requestArgs, token); var clientAssertion = _jwtTokenParser.Parse(response); if (!_tokenResponseValidator.IsValid(clientAssertion)) { throw new UnsuccessfulResponseException("Token which was retrieved from SO is corrupted."); } return(TokenConvert.DeserializeClaim <List <CertificateAuthority> >( clientAssertion.JwtSecurityToken, "trusted_list")); } catch (UnsuccessfulResponseException) { throw; } catch (Exception e) { throw new UnsuccessfulResponseException("Trusted list request was unsuccessful.", e); } }
public void DeserializeClaim_JwtSecurityTokenDoesNotContainProvidedClaim_Throws() { var jwtToken = CreateCapabilitiesToken(); Action act = () => TokenConvert.DeserializeClaim <dynamic>(jwtToken, "invalid"); act.Should().Throw <InvalidOperationException>(); }
public void DeserializeClaim_NullJwtSecurityToken_Throws() { JwtSecurityToken jwtToken = null; Action act = () => TokenConvert.DeserializeClaim <dynamic>(jwtToken, "not_null"); act.Should().Throw <ArgumentNullException>(); }
public void DeserializeClaim_InvalidClaimName_Throws(string claimName) { var jwtToken = new JwtSecurityToken(); Action act = () => TokenConvert.DeserializeClaim <dynamic>(jwtToken, claimName); act.Should().Throw <ArgumentNullException>(); }
public void DeserializeClaim_ValidClaimButInvalidType_ReturnsObjectWithNulls() { var jwtToken = CreateCapabilitiesToken(); var result = TokenConvert.DeserializeClaim <CertificateAuthority>(jwtToken, "capabilities_info"); result.Should().NotBeNull(); result.Subject.Should().BeNull(); result.CertificateFingerprint.Should().BeNull(); result.Validity.Should().BeNull(); result.Status.Should().BeNull(); }
public void DeserializeClaim_ClaimWhichContainsArrayPayload_ReturnsValidObject() { var jwtToken = CreateTrustedListToken(); var result = TokenConvert.DeserializeClaim <CertificateAuthority[]>(jwtToken, "trusted_list"); result.Should().HaveCount(7); var ca = result.First(); ca.Subject.Should().Be("C=NL, O=Staat der Nederlanden, CN=TEST Staat der Nederlanden Organisatie Services CA - G3"); ca.CertificateFingerprint.Should().Be("DC13FC94FF0149DE1B07F7965F655AED54C6A6BDA7ADF71A732FFCFABC454C7A"); ca.Validity.Should().Be("valid"); ca.Status.Should().Be("granted"); }
public void SuccessfullyEncryptsAndDecrypts() { var testObj = new Credentials { Username = "******", Password = "******" }; var key = Guid.NewGuid().ToString(); var token = TokenConvert.SerializeEncryptedToken(testObj, key, "123123salt 1"); var newObj = TokenConvert.DeserializeEncryptedToken <Credentials>(token, key, "123123salt 1"); newObj.Username.Should().Be("test1"); newObj.Password.Should().Be("test2"); }
public void DeserializeClaim_ValidClaimAndValidType_ReturnsValidObject() { var jwtToken = CreateCapabilitiesToken(); var result = TokenConvert.DeserializeClaim <CapabilitiesResponse>(jwtToken, "capabilities_info"); result.Should().NotBeNull(); result.PartyId.Should().Be("EU.EORI.NL000000003"); result.Roles.Should().HaveCount(1); result.SupportedVersions.Should().NotBeNull(); result.SupportedVersions.Should().HaveCount(1); result.SupportedVersions.First().Version.Should().Be("1.7"); result.SupportedVersions.First().SupportedFeatures.First().Public.Should().HaveCount(4); var firstPublicFeature = result.SupportedVersions.First().SupportedFeatures.First().Public.First(); firstPublicFeature.Id.Should().Be("A51D413F-B3CC-477D-96C4-E37A9003BFE3"); firstPublicFeature.Feature.Should().Be("capabilities"); firstPublicFeature.Description.Should().Be("Retrieves iSHARE capabilities"); firstPublicFeature.Url.Should().Be("https://w13.isharetest.net/capabilities"); firstPublicFeature.TokenEndpoint.Should().Be("https://w13.isharetest.net/connect/token"); result.SupportedVersions.First().SupportedFeatures.First().Restricted.Should().HaveCount(0); }
public void FailsWithDifferentSalts() { var testObj = new Credentials { Username = "******", Password = "******" }; var key = Guid.NewGuid().ToString(); var token = TokenConvert.SerializeEncryptedToken(testObj, key, "123123salt 1"); var success = true; try { var newObj = TokenConvert.DeserializeEncryptedToken <Credentials>(token, key, "123123salt 2"); } catch { success = false; } success.Should().BeFalse(); }
public async Task <PartiesResponse> GetAsync(PartiesRequestArgs args, CancellationToken token) { try { var requestArgs = MapIntoTokenSendRequestArgs(args); var response = await _client.SendRequestAsync(requestArgs, token); var clientAssertion = _jwtTokenParser.Parse(response); if (!_tokenResponseValidator.IsValid(clientAssertion)) { throw new UnsuccessfulResponseException("Token which was retrieved from SO is corrupted."); } return(TokenConvert.DeserializeClaim <PartiesResponse>(clientAssertion.JwtSecurityToken, "parties_info")); } catch (UnsuccessfulResponseException) { throw; } catch (Exception e) { throw new UnsuccessfulResponseException("Parties request was unsuccessful.", e); } }
public async Task <IActionResult> Config([FromBody] IntegrationSetupRequest request) { request.AdditionalProperties.TryGetValue("voicify-app", out var voicifyAppId); request.AdditionalProperties.TryGetValue("quick-base-token", out var quickbaseToken); request.AdditionalProperties.TryGetValue("quick-base-realm", out var quickbaseRealm); // validate inputs if (string.IsNullOrEmpty(voicifyAppId)) { return(BadRequest(new[] { "You must select a Voicify app." })); } if (string.IsNullOrEmpty(quickbaseToken)) { return(BadRequest(new[] { "You must provide a user token for Quick Base." })); } if (string.IsNullOrEmpty(quickbaseRealm)) { return(BadRequest(new[] { "You must provide a Quick Base realm." })); } var voicifyConfig = new Configuration { BasePath = "https://cms.voicify.com", DefaultHeader = new Dictionary <string, string> { { "Authorization", $"Bearer {request.AccessToken}" } } }; using var client = new HttpClient(); var appProvider = new QuickBaseAppProvider(client, quickbaseRealm, quickbaseToken); var tableProvider = new QuickBaseTableProvider(client, quickbaseRealm, quickbaseToken); var fieldProvider = new QuickBaseFieldProvider(client, quickbaseRealm, quickbaseToken); var appApi = new ApplicationApi(voicifyConfig); var userApi = new UserApi(voicifyConfig); var webhookApi = new WebhookApi(voicifyConfig); var orgApi = new OrganizationApi(voicifyConfig); // get voicify org var orgs = await orgApi.GetForUserAsync(); var org = orgs.FirstOrDefault(o => o.Id == request.OrganizationId); // get voicify app var app = await appApi.FindApplicationAsync(voicifyAppId); // create quick base app var appResult = await appProvider.CreateApp(new NewQuickBaseAppRequest { AssignToken = true, Description = app.Description, Name = app.Name }); if (appResult.ResultType != ResultType.Ok) { return(BadRequest(appResult.Errors)); } // create tables var faqTableResult = await tableProvider.CreateTable(appResult.Data.Id, new NewTableRequest { Name = "Questions and Answers", Description = "Free form question and answer options", PluralRecordName = "Questions and Answers", SingleRecordName = "Question and Answer" }); if (faqTableResult.ResultType != ResultType.Ok) { return(BadRequest(faqTableResult.Errors)); } var requestTableResult = await tableProvider.CreateTable(appResult.Data.Id, new NewTableRequest { Name = "Conversational Request Data", Description = "Data from the requests made by users to the voice/bot application", PluralRecordName = "Requests", SingleRecordName = "Request" }); if (requestTableResult.ResultType != ResultType.Ok) { return(BadRequest(requestTableResult.Errors)); } // create fields for tables var results = await Task.WhenAll(new List <Task <Result <(QuickBaseField Field, string TableId)> > > { fieldProvider.CreateField(faqTableResult.Data.Id, new NewFieldRequest { Label = "question" }), fieldProvider.CreateField(faqTableResult.Data.Id, new NewFieldRequest { Label = "answer" }), fieldProvider.CreateField(faqTableResult.Data.Id, new NewFieldRequest { Label = "foregroundImageUrl" }), fieldProvider.CreateField(faqTableResult.Data.Id, new NewFieldRequest { Label = "followUpPrompt" }), fieldProvider.CreateField(faqTableResult.Data.Id, new NewFieldRequest { Label = "nextItemRecordIds" }), fieldProvider.CreateField(requestTableResult.Data.Id, new NewFieldRequest { Label = "applicationId" }), fieldProvider.CreateField(requestTableResult.Data.Id, new NewFieldRequest { Label = "requestDate" }), fieldProvider.CreateField(requestTableResult.Data.Id, new NewFieldRequest { Label = "platform" }), fieldProvider.CreateField(requestTableResult.Data.Id, new NewFieldRequest { Label = "requestId" }), fieldProvider.CreateField(requestTableResult.Data.Id, new NewFieldRequest { Label = "userId" }), fieldProvider.CreateField(requestTableResult.Data.Id, new NewFieldRequest { Label = "sessionId" }), fieldProvider.CreateField(requestTableResult.Data.Id, new NewFieldRequest { Label = "slots" }), fieldProvider.CreateField(requestTableResult.Data.Id, new NewFieldRequest { Label = "contentItemId" }), fieldProvider.CreateField(requestTableResult.Data.Id, new NewFieldRequest { Label = "featureTypeId" }), }); // create API user in voicify var apiUser = await userApi.CreateApiUserAsync(new NewApiUserRequest(request.OrganizationId)); // create token with api user credentials var token = TokenConvert.SerializeEncryptedToken(new WebhookTokenModel { VoicifyOrganizationId = org.Id, VoicifyOrganizationSecret = org.Secret, VoicifyApiUserName = apiUser.Username, VoicifyApiUserSecret = apiUser.Password, QuickBaseToken = quickbaseToken, QuickBaseRealm = quickbaseRealm, VoicifyApplicationId = voicifyAppId, QuickBaseAppId = appResult.Data.Id, QuickBaseFaqTableId = faqTableResult.Data.Id, QuickBaseRequestTableId = requestTableResult.Data.Id, QuickBaseRequestTableMatrix = results.Where(r => r.Data.TableId == requestTableResult.Data.Id) .ToDictionary( d => d.Data.Field.Label, d => d.Data.Field.Id.ToString()), QuickBaseFaqTableMatrix = results.Where(r => r.Data.TableId == faqTableResult.Data.Id) .ToDictionary( d => d.Data.Field.Label, d => d.Data.Field.Id.ToString()) }, _config.GetValue <string>("EncodingKey") ?? "whoops"); // create webhook in voicify var webhook = await webhookApi.CreateWebhookAsync(request.OrganizationId, new NewWebhookRequest( title : $"{app?.Name ?? "App"} - Quick Base Request Event", description : "Creates event records in Quick Base when a request is received through Voicify. Use this token for Quick Base pipelines as well", url : "https://quick-base-voicify-sync.azurewebsites.net/api/voicify/contentHit", webhookTypeId : "53b40ef2-769c-46e6-bc99-c709e7600c03", // Content Hit Event webhook type accessToken : token )); // add webhook to app var appWebhook = await appApi.AddWebhookAsync(voicifyAppId, webhook.Id, new WebhookParametersRequest(values : new Dictionary <string, string>(), userDefinedParameters : new Dictionary <string, string>())); return(Ok()); }
public async Task <IActionResult> AddItem([FromHeader] string authorization, [FromBody] QuickBaseQuestionAnswerItem item) { try { var tokenModel = TokenConvert.DeserializeEncryptedToken <WebhookTokenModel>(authorization, _config.GetValue <string>("EncodingKey") ?? "whoops"); var authApi = new AuthenticationApi("https://cms.voicify.com"); // sign in with api user creds to get token var tokenResponse = await authApi.AuthenticateAsync(tokenModel.VoicifyOrganizationId, tokenModel.VoicifyOrganizationSecret, "password", tokenModel.VoicifyApiUserName, tokenModel.VoicifyApiUserSecret); var voicifyConfig = new Configuration { BasePath = "https://cms.voicify.com", DefaultHeader = new Dictionary <string, string> { { "Authorization", $"Bearer {tokenResponse.AccessToken}" } } }; var featureApi = new FeatureApi(voicifyConfig); var questionAnswerApi = new QuestionAnswerApi(voicifyConfig); var mediaItemApi = new MediaItemApi(voicifyConfig); MediaItemModel mediaItem = null; if (!string.IsNullOrEmpty(item?.ForegroundImageUrl) && Uri.TryCreate(item.ForegroundImageUrl, UriKind.Absolute, out var imageUri)) { // TODO: once voicify allows external urls through this api, send it up //mediaItem = await mediaItemApi.CreateMediaItem_0Async(tokenModel.VoicifyApplicationId, new NewMediaItemRequest(item.ForegroundImageUrl, item.ForegroundImageUrl, item.ForegroundImageUrl, "")); } // get root feature of app var features = await featureApi.GetFeaturesForApplicationAsync(tokenModel.VoicifyApplicationId); var rootFeature = features.FirstOrDefault(af => string.IsNullOrEmpty(af.ParentId)); // add question answer to root feature var faq = await questionAnswerApi.CreateFullContentItemAsync(new QuestionAnswerModel( applicationFeatureId : rootFeature.Id, applicationId : rootFeature.ApplicationId, isLive : true, title : item.Question, questionSet : new List <QuestionModel> { new QuestionModel(content : item.Question) }, responses : new List <AnswerModel> { new AnswerModel( content : item.Answer, largeImage : mediaItem, followUp : string.IsNullOrEmpty(item.FollowUpPrompt) ? null : new FollowUpModel(applicationId : tokenModel.VoicifyApplicationId, content : item.FollowUpPrompt)) })); } catch (Exception ex) { Console.WriteLine(ex); } return(Ok()); }