diff --git a/src/components/MarketplaceList.vue b/src/components/MarketplaceList.vue index ed5bba8..0aed32e 100644 --- a/src/components/MarketplaceList.vue +++ b/src/components/MarketplaceList.vue @@ -19,7 +19,7 @@
-
@@ -113,21 +113,24 @@ export default { computed: { ...mapGetters('mainStore', ['getMarketPlaceApps']), services() { - return this.getMarketPlaceApps + return this.getMarketPlaceApps.filter(app => !!app.issuerDid) } - }, - beforeMount() { - }, methods: { - ...mapMutations("mainStore", ["updateAnMarketPlaceApp", 'insertMarketplaceApps']), + ...mapMutations("mainStore", ['insertMarketplaceApps']), onIssuerToggle(eachOrg) { + // Toggle selected state and commit to the store + const updated = this.getMarketPlaceApps.map(x => + x.appId === eachOrg.appId ? { ...x, selected: !x.selected } : x + ) + this.insertMarketplaceApps(updated) + const updatedOrg = updated.find(x => x.appId === eachOrg.appId) this.$emit('selectedServiceEvent', { - issuerDid: eachOrg.issuerDid, - selected: eachOrg.selected, - appId: eachOrg.appId + issuerDid: updatedOrg.issuerDid, + selected: updatedOrg.selected, + appId: updatedOrg.appId }) - }, + }, formattedAppName(appName) { if (appName == "" || appName == undefined) appName = "No app name"; return this.truncate(appName, 25); @@ -140,19 +143,6 @@ export default { return domain } }, - serviceSelected(eachOrg) { - if (eachOrg) { - const t = this.getMarketPlaceApps.map((x) => { - if (x.appId === eachOrg.appId) { - x['selected'] = x['selected'] && x['selected'] == true ? false : true; - } - return x - }) - this.insertMarketplaceApps(t) - this.$emit('selectedServiceEvent', eachOrg); - } - - } }, mixins: [UtilsMixin], diff --git a/src/components/settings/OnlySSIApps.vue b/src/components/settings/OnlySSIApps.vue index 4617939..25be55d 100644 --- a/src/components/settings/OnlySSIApps.vue +++ b/src/components/settings/OnlySSIApps.vue @@ -209,7 +209,13 @@ - +
+ + + +
@@ -814,8 +820,7 @@ export default { const appModel = this.getAppByAppId(appId); //// commeting it for time being - // appModel.whitelistedCors = appModel.whitelistedCors.toString(); - appModel.whitelistedCors = '*'; + appModel.whitelistedCors = appModel.whitelistedCors.toString(); Object.assign(this.appModel, { ...appModel }); this.selectedAssociatedSSIAppId = appModel.dependentServices[0]; @@ -874,7 +879,11 @@ export default { m.push(messages.APPLICATION.ENTER_DOMAIN_ORGIN); } else { try { - const t = new URL(this.appModel.domain); + let domain = this.appModel.domain?.trim(); + if (domain && !domain.startsWith("http://") && !domain.startsWith("https://")) { + domain = `https://${domain}`; + } + const t = new URL(domain); if (!t.origin || t.host == "") { throw new Error(); } @@ -1235,6 +1244,7 @@ export default { domain: "", hasDomainVerified: false, domainLinkageCredentialString: "", + whitelistedCors: "*" }; this.selectedAssociatedSSIAppId = ""; this.domain = ""; diff --git a/src/mixins/fieldValidation.js b/src/mixins/fieldValidation.js index aa19780..f23e82a 100644 --- a/src/mixins/fieldValidation.js +++ b/src/mixins/fieldValidation.js @@ -1,7 +1,7 @@ import validURL from 'valid-url' export function isValidURL(str) { - return validURL.isUri(str); + return validURL.isUri(str.trim()); } // export function isDomain(str) // { diff --git a/src/store/mainStore.js b/src/store/mainStore.js index d33904f..1053700 100644 --- a/src/store/mainStore.js +++ b/src/store/mainStore.js @@ -1310,7 +1310,6 @@ const mainStore = { const authToken = getters.getSelectedService.access_token const headers = UtilsMixin.methods.getKycServiceHeader(authToken); const data = getters.getWidgetnConfig; - data['issuerVerificationMethodId'] = getters.getWidgetnConfig.issuerDID + '#key-1'; fetch(url, { method: 'POST', headers, @@ -1367,7 +1366,6 @@ const mainStore = { const authToken = getters.getSelectedService.access_token const headers = UtilsMixin.methods.getKycServiceHeader(authToken); const data = getters.getWidgetnConfig; - data['issuerVerificationMethodId'] = getters.getWidgetnConfig.issuerDID + '#key-1'; fetch(url, { method: 'PATCH', headers, diff --git a/src/views/Apps.vue b/src/views/Apps.vue index ef82e57..aaedbcf 100644 --- a/src/views/Apps.vue +++ b/src/views/Apps.vue @@ -373,13 +373,13 @@
- + placeholder="http://your-domain.com,http://test.com"> +
@@ -934,6 +934,7 @@ import { sanitizeUrl } from "../utils/common"; // import DeployOnChainKYC from "../components/deploy-onchain-kyc-popup/deploy.vue"; import DomainLinkage from "@hypersign-protocol/domain-linkage-verifier"; import config from "../config"; +import {isValidOrigin} from '../mixins/fieldValidation.js'; export default { name: "AppList", computed: { @@ -1290,8 +1291,10 @@ export default { const appModel = this.getAppByAppId(appId); //// commeting it for time being - // appModel.whitelistedCors = appModel.whitelistedCors.toString(); - appModel.whitelistedCors = '*'; + if (appModel.services && appModel.services.length > 0) { + this.selectedServiceId = appModel.services[0].id; + } + appModel.whitelistedCors = appModel.whitelistedCors.toString(); Object.assign(this.appModel, { ...appModel }); this.selectedAssociatedSSIAppId = appModel.dependentServices[0]; @@ -1334,23 +1337,24 @@ export default { } } - // console.log('----------------------------------------------------------------') - // console.log(this.appModel.whitelistedCors) - // if (!Array.isArray(this.appModel.whitelistedCors)) { - // const newArray = this.appModel.whitelistedCors?.split(",").filter((x) => x != " ").map((x) => x.trim()); - // for (let i = 0; i < newArray.length; i++) { - // if (!isValidOrigin(newArray[i])) { - // m.push(messages.APPLICATION.INVALID_CORS); - // break; - // } - // } - // } - + if (!Array.isArray(this.appModel.whitelistedCors)) { + const newArray = this.appModel.whitelistedCors?.split(",").map((x) => x.trim()).filter((x) => x.length > 0); + for (let i = 0; i < newArray.length; i++) { + if (!isValidOrigin(newArray[i])) { + m.push(messages.APPLICATION.INVALID_CORS); + break; + } + } + } if (!this.appModel.domain) { m.push(messages.APPLICATION.ENTER_DOMAIN_ORGIN); } else { try { - const t = new URL(this.appModel.domain); + let domain = this.appModel.domain?.trim(); + if (domain && !domain.startsWith("http://") && !domain.startsWith("https://")) { + domain = `https://${domain}`; + } + const t = new URL(domain); if (!t.origin || t.host == "") { throw new Error(); } diff --git a/src/views/ServiceConfig.vue b/src/views/ServiceConfig.vue index bf6403a..98d0f25 100644 --- a/src/views/ServiceConfig.vue +++ b/src/views/ServiceConfig.vue @@ -217,17 +217,72 @@ --> - + +
+ DID Configuration +
+
+
+ + - + + — Select a DID — + + {{ did }} + + + + + + + + + + - - + + + + + {{ formData.issuerDid ? '— Select a Verification Method —' : '— Select a DID first —' }} + + + {{ vm.id }} ({{ vm.type }}) + + + + - --> + @@ -272,7 +327,7 @@ import HfPopUp from "../components/element/hfPopup.vue"; import UtilsMixin from '../mixins/utils' import messages from "../mixins/messages"; -import { mapGetters, mapActions } from 'vuex/dist/vuex.common.js'; +import { mapGetters, mapActions, mapMutations, mapState } from 'vuex/dist/vuex.common.js'; export default { name: "ServiceConfig", data() { @@ -282,6 +337,8 @@ export default { appIdToGenerateSecret: "", linkedAppErrorMessage: "", showVerificationInfo: false, + associatedSSIServiceDIDs: [], + issuerVerificationMethodIds: [], formData: { }, @@ -295,7 +352,8 @@ export default { }; }, computed: { - ...mapGetters("mainStore", ["getSelectedService"]), + ...mapGetters("mainStore", ["getSelectedService", "getAppsWithSSIServices"]), + ...mapState({ widgetConfig: state => state.mainStore.widgetConfig }), formattedErrorMessage() { return this.linkedAppErrorMessage.replace(/\n/g, "
"); }, @@ -316,15 +374,30 @@ export default { ? "hypersign-domain-verification.did=" + this.formData.issuerDid : null; }, + selectedVerificationMethodType() { + if (!this.formData.issuerVerificationMethodId || !this.issuerVerificationMethodIds.length) { + return null; + } + const vm = this.issuerVerificationMethodIds.find( + v => v.id === this.formData.issuerVerificationMethodId + ); + return vm ? vm.type : null; + }, }, components: { HfPopUp }, - created() { + async created() { this.formData = { ...this.getSelectedService }; this.isProd = this.formData.env === "prod"; - - console.log(this.isProd) + + // Fetch DIDs for display/selection + await this.fetchDIDsForDisplay(); + + // If DID is already set, fetch verification methods for display + if (this.formData.issuerDid) { + await this.fetchVerificationMethodsForDisplay(); + } }, watch: { isProd(newVal) { @@ -332,10 +405,149 @@ export default { } }, methods: { - ...mapActions("mainStore", ["updateAnAppOnServer", "deleteAnAppOnServer"]), - startEdit() { + ...mapActions("mainStore", ["updateAnAppOnServer", "deleteAnAppOnServer", "fetchDIDsForAService", "resolveDIDForAKycService", "updateAppsWidgetConfig"]), + ...mapMutations("mainStore", ["setWidgetConfig"]), + async fetchDIDsForDisplay() { + try { + const ssiServiceId = this.formData.dependentServices && this.formData.dependentServices[0]; + if (!ssiServiceId) return; + + const associatedSSIService = this.getAppsWithSSIServices.find( + (x) => x.appId === ssiServiceId + ); + + if (!associatedSSIService) return; + + const payload = { + tenantUrl: associatedSSIService.tenantUrl, + accessToken: associatedSSIService.access_token, + }; + const allDIDs = await this.fetchDIDsForAService(payload); + + if (allDIDs && Array.isArray(allDIDs) && allDIDs.length > 0) { + this.associatedSSIServiceDIDs = allDIDs; + } else { + this.associatedSSIServiceDIDs = []; + } + } catch (e) { + console.error('Error fetching DIDs for display:', e); + } + }, + async fetchVerificationMethodsForDisplay() { + try { + const ssiServiceId = this.formData.dependentServices && this.formData.dependentServices[0]; + if (!ssiServiceId) return; + + const associatedSSIService = this.getAppsWithSSIServices.find( + (x) => x.appId === ssiServiceId + ); + + if (!associatedSSIService) return; + + const payload = { + tenantUrl: associatedSSIService.tenantUrl, + accessToken: associatedSSIService.access_token, + did: this.formData.issuerDid + }; + const didDocument = await this.resolveDIDForAKycService(payload); + this.issuerVerificationMethodIds = didDocument.verificationMethod.filter(vm => vm); + } catch (e) { + // Silently fail for display purposes + console.error('Error fetching verification methods for display:', e); + } + }, + async fetchDIDs() { + try { + // Find the associated SSI service + const ssiServiceId = this.formData.dependentServices && this.formData.dependentServices[0]; + if (!ssiServiceId) { + throw new Error('No associated SSI service found'); + } + + const associatedSSIService = this.getAppsWithSSIServices.find( + (x) => x.appId === ssiServiceId + ); + + if (!associatedSSIService) { + throw new Error('Associated SSI service not found'); + } + + this.isLoading = true; + const payload = { + tenantUrl: associatedSSIService.tenantUrl, + accessToken: associatedSSIService.access_token, + }; + const allDIDs = await this.fetchDIDsForAService(payload); + + if (allDIDs && Array.isArray(allDIDs) && allDIDs.length > 0) { + // DIDs are returned as strings, not objects + this.associatedSSIServiceDIDs = allDIDs; + } else { + this.associatedSSIServiceDIDs = []; + this.notifyErr('No DIDs found for the associated SSI service'); + } + this.isLoading = false; + } catch (e) { + this.isLoading = false; + console.error('Error fetching DIDs:', e); + this.notifyErr(e.message); + } + }, + async resolveDid(event) { + try { + let did; + if (typeof event === 'string') { + did = event; + } else { + did = event.target.value; + } + + if (!did) { + this.issuerVerificationMethodIds = []; + return; + } + + // Find the associated SSI service + const ssiServiceId = this.formData.dependentServices && this.formData.dependentServices[0]; + if (!ssiServiceId) { + throw new Error('No associated SSI service found'); + } + + const associatedSSIService = this.getAppsWithSSIServices.find( + (x) => x.appId === ssiServiceId + ); + + if (!associatedSSIService) { + throw new Error('Associated SSI service not found'); + } + + this.isLoading = true; + const payload = { + tenantUrl: associatedSSIService.tenantUrl, + accessToken: associatedSSIService.access_token, + did + }; + const didDocument = await this.resolveDIDForAKycService(payload); + this.issuerVerificationMethodIds = didDocument.verificationMethod.filter(vm => vm); + this.isLoading = false; + } catch (e) { + this.isLoading = false; + this.notifyErr(e.message); + } + }, + async startEdit() { this.backupData = JSON.parse(JSON.stringify(this.formData)); this.isEditing = true; + + // Fetch DIDs if not already loaded + if (!this.associatedSSIServiceDIDs.length) { + await this.fetchDIDs(); + } + + // If DID is already set, resolve it to get verification methods + if (this.formData.issuerDid) { + await this.resolveDid(this.formData.issuerDid); + } }, cancelEdit() { this.formData = JSON.parse(JSON.stringify(this.backupData)); @@ -353,6 +565,18 @@ export default { this.isLoading = true; await this.updateAnAppOnServer({ ...this.formData }) + + // Sync issuerDid and issuerVerificationMethodId into widget config + if (this.formData.issuerDid && Object.keys(this.widgetConfig).length > 0) { + const updatedWidgetConfig = { + ...this.widgetConfig, + issuerDID: this.formData.issuerDid, + issuerVerificationMethodId: this.formData.issuerVerificationMethodId || this.widgetConfig.issuerVerificationMethodId, + } + this.setWidgetConfig(updatedWidgetConfig) + await this.updateAppsWidgetConfig() + } + this.notifySuccess("Service configuration updated successfully!"); }catch(err){ this.notifyErr(err.message); diff --git a/src/views/playground/WidgetConfig/Index.vue b/src/views/playground/WidgetConfig/Index.vue index d7e22dd..736f8c4 100644 --- a/src/views/playground/WidgetConfig/Index.vue +++ b/src/views/playground/WidgetConfig/Index.vue @@ -146,7 +146,7 @@ ul {
- @@ -156,10 +156,10 @@ ul {