diff --git a/cornucopia.owasp.org/src/domain/mapping/mappingController.ts b/cornucopia.owasp.org/src/domain/mapping/mappingController.ts
index 008fe71e7..0083cb8ea 100644
--- a/cornucopia.owasp.org/src/domain/mapping/mappingController.ts
+++ b/cornucopia.owasp.org/src/domain/mapping/mappingController.ts
@@ -53,6 +53,10 @@ export class MappingController {
public getCardMappings(card : string, addition : number = 0) : Mapping
{
+ if (!this.mapping || !this.mapping.suits) {
+ return {} as Mapping;
+ }
+
for(let i = 0 ; i < this.mapping.suits.length ; i++)
{
for(let j = 0 ; j < this.mapping.suits[i].cards.length ; j++)
diff --git a/cornucopia.owasp.org/src/lib/components/cardFound.svelte b/cornucopia.owasp.org/src/lib/components/cardFound.svelte
index 51f401cd0..e77615a54 100644
--- a/cornucopia.owasp.org/src/lib/components/cardFound.svelte
+++ b/cornucopia.owasp.org/src/lib/components/cardFound.svelte
@@ -56,10 +56,10 @@
{$t('cards.cardFound.a')}
- {#if card.edition == 'webapp' && card.value != 'A' && card.value != 'B'}
+ {#if card.edition == 'webapp'}
{/if}
- {#if card.edition == 'mobileapp' && card.value != 'A' && card.value != 'B'}
+ {#if card.edition == 'mobileapp'}
{/if}
{#key card}
diff --git a/cornucopia.owasp.org/src/lib/components/cardPreview.svelte b/cornucopia.owasp.org/src/lib/components/cardPreview.svelte
index 63c347cb5..2641cc08c 100644
--- a/cornucopia.owasp.org/src/lib/components/cardPreview.svelte
+++ b/cornucopia.owasp.org/src/lib/components/cardPreview.svelte
@@ -53,10 +53,10 @@
{#if mapping}
{card?.card ?? card?.value}
{card?.desc}
- {#if card?.edition == 'webapp' && card?.value != 'A' && card?.value != 'B'}
+ {#if card?.edition == 'webapp'}
{/if}
- {#if card?.edition == 'mobileapp' && card?.value != 'A' && card?.value != 'B'}
+ {#if card?.edition == 'mobileapp'}
{/if}
{:else if card?.suitName == 'WILD CARD'}
diff --git a/cornucopia.owasp.org/src/lib/components/mobileAppCardTaxonomy.svelte b/cornucopia.owasp.org/src/lib/components/mobileAppCardTaxonomy.svelte
index 735958ccc..114f4050c 100644
--- a/cornucopia.owasp.org/src/lib/components/mobileAppCardTaxonomy.svelte
+++ b/cornucopia.owasp.org/src/lib/components/mobileAppCardTaxonomy.svelte
@@ -57,33 +57,37 @@
- {#if card.value != 'A' && card.value != 'B'}
+ {#if mappings }
{$t('cards.mobileAppCardTaxonomy.h1.1')}
+ {#if mappings.owasp_masvs}
+ {/if}
+ {#if mappings.owasp_mastg}
+ {/if}
+ {#if mappings.capec}
-
{/if}
-
- {#if card.value != 'A' && card.value != 'B'}
-
+ {#if mappings.safecode}
+
{/if}
{$t('cards.mobileAppCardTaxonomy.h1.2')}
- {#if card.value != 'A' && card.value != 'B'}
+ {#if attacks }
{/if}
+ {/if}
diff --git a/cornucopia.owasp.org/src/lib/components/webAppCardTaxonomy.svelte b/cornucopia.owasp.org/src/lib/components/webAppCardTaxonomy.svelte
index 2cd31998f..70270902b 100644
--- a/cornucopia.owasp.org/src/lib/components/webAppCardTaxonomy.svelte
+++ b/cornucopia.owasp.org/src/lib/components/webAppCardTaxonomy.svelte
@@ -61,6 +61,8 @@
}
let mappings: WebAppMapping = $state(controller.getWebAppCardMappings(card.id));
let attacks: Attack[] = $state(GetCardAttacks(card.id));
+
+ let hasMappings = $derived(mappings && Object.keys(mappings).length > 1);
run(() => {
mappings = controller.getWebAppCardMappings(card.id);
@@ -68,41 +70,53 @@
});
- {#if card.value != 'A' && card.value != 'B'}
+ {#if hasMappings }
{$t('cards.webAppCardTaxonomy.h1.1')}
+ {#if mappings.stride}
+ {/if}
+ {#if mappings.owasp_asvs}
+ {/if}
+ {#if mappings.capec}
+ {/if}
+ {#if mappings.owasp_dev_guide}
+ {/if}
+ {#if mappings.owasp_appsensor}
+ {/if}
+ {#if mappings.safecode}
"https://safecode.org/publication/SAFECode_Agile_Dev_Security0712.pdf"}
/>
+ {/if}
{/if}
ASVS (4.0) Cheat Sheet Series Index
- {#if card.value != 'A' && card.value != 'B'}
+ {#if hasMappings && mappings.owasp_asvs}
+String(s).split('.').slice(0, 2).join('.')))]}>
{/if}
{$t('cards.webAppCardTaxonomy.h1.2')}
diff --git a/cornucopia.owasp.org/src/lib/services/deckService.ts b/cornucopia.owasp.org/src/lib/services/deckService.ts
index 0c2ffde99..efbdfb740 100644
--- a/cornucopia.owasp.org/src/lib/services/deckService.ts
+++ b/cornucopia.owasp.org/src/lib/services/deckService.ts
@@ -115,11 +115,29 @@ export class DeckService {
{
const decks = new Map();
const editions = DeckService.decks;
+
+ // Load all mappings if not already loaded
+ if (DeckService.mappings.length === 0) {
+ this.getCardMappingDataAllVersions();
+ }
+
editions.forEach((deck) => {
- decks.set(
- `${deck.edition}-${deck.version}`, DeckService.mappings.find((mapping) => mapping?.version == deck.version && mapping?.edition == deck.edition)?.data || this.getCardMappingDataAllVersions()
- );
+ let mappingData = DeckService.mappings.find((mapping) => mapping?.version == deck.version && mapping?.edition == deck.edition)?.data;
+ // If not found in cache, try to load it
+ if (!mappingData) {
+ try {
+ const yamlData = fs.readFileSync(`${__dirname}${DeckService.path}${DeckService.getEdition(deck.edition)}-mappings-${deck.version}.yaml`, 'utf8');
+ mappingData = yaml.load(yamlData);
+ DeckService.mappings.push({edition: deck.edition, version: deck.version, data: mappingData});
+ } catch (e) {
+ console.error(`Failed to load mapping for ${deck.edition}-${deck.version}:`, e);
+ }
+ }
+
+ if (mappingData) {
+ decks.set(`${deck.edition}-${deck.version}`, mappingData);
+ }
});
return decks;
}
diff --git a/cornucopia.owasp.org/src/routes/card/[edition]/+page.server.ts b/cornucopia.owasp.org/src/routes/card/[edition]/+page.server.ts
index 161953536..3ec4df2e7 100644
--- a/cornucopia.owasp.org/src/routes/card/[edition]/+page.server.ts
+++ b/cornucopia.owasp.org/src/routes/card/[edition]/+page.server.ts
@@ -3,7 +3,6 @@ import { error } from '@sveltejs/kit';
import { SuitController } from '$domain/suit/suitController';
import { FileSystemHelper } from '$lib/filesystem/fileSystemHelper';
-const editions = ["webapp", "mobileapp"];
export const load = (({ params }) => {
const edition = params?.edition;
if (!DeckService.hasEdition(edition)) error(
diff --git a/cornucopia.owasp.org/src/routes/card/[edition]/[card]/+page.server.ts b/cornucopia.owasp.org/src/routes/card/[edition]/[card]/+page.server.ts
index 88b8dd98f..71f85e15e 100644
--- a/cornucopia.owasp.org/src/routes/card/[edition]/[card]/+page.server.ts
+++ b/cornucopia.owasp.org/src/routes/card/[edition]/[card]/+page.server.ts
@@ -3,8 +3,6 @@ import { error } from '@sveltejs/kit';
import { DeckService } from "$lib/services/deckService";
import type { Route } from "$domain/routes/route";
-const editions = ["webapp", "mobileapp"];
-
export const load = (({ params }) => {
const edition = params?.edition;
const version = edition == 'webapp' ? '2.2' : '1.1';
diff --git a/cornucopia.owasp.org/src/routes/card/[edition]/[card]/[version]/+page.server.ts b/cornucopia.owasp.org/src/routes/card/[edition]/[card]/[version]/+page.server.ts
index be5a3b171..f65874b73 100644
--- a/cornucopia.owasp.org/src/routes/card/[edition]/[card]/[version]/+page.server.ts
+++ b/cornucopia.owasp.org/src/routes/card/[edition]/[card]/[version]/+page.server.ts
@@ -3,10 +3,6 @@ import { error } from '@sveltejs/kit';
import { DeckService } from "$lib/services/deckService";
import type { Route } from "$domain/routes/route";
-const editions = ["webapp", "mobileapp"];
-const languages = ["en", "no_nb", "nl", "es", "pt_pt", "pt_br", "ru", "fr", "it", "hu"];
-const versions = ["3.0", "2.2", "1.0"];
-
export const load = (({ params }) => {
const edition = params?.edition;
const version = params?.version;
diff --git a/cornucopia.owasp.org/src/routes/card/[edition]/[card]/[version]/[lang]/+page.server.ts b/cornucopia.owasp.org/src/routes/card/[edition]/[card]/[version]/[lang]/+page.server.ts
index 9e88d3e49..282f3c4e2 100644
--- a/cornucopia.owasp.org/src/routes/card/[edition]/[card]/[version]/[lang]/+page.server.ts
+++ b/cornucopia.owasp.org/src/routes/card/[edition]/[card]/[version]/[lang]/+page.server.ts
@@ -3,10 +3,6 @@ import { DeckService } from "$lib/services/deckService";
import { error } from '@sveltejs/kit';
import type { Route } from "$domain/routes/route";
-const editions = ["webapp", "mobileapp"];
-const languages = ["en", "no_nb", "nl", "es", "pt_pt", "pt_br", "ru", "fr", "it", "hu"];
-const versions = ["3.0", "2.2", "1.0"];
-
export const load = (({ params }) => {
const edition = params?.edition;
const version = params?.version;
diff --git a/cornucopia.owasp.org/svelte.config.js b/cornucopia.owasp.org/svelte.config.js
index 297a1c719..38006d249 100644
--- a/cornucopia.owasp.org/svelte.config.js
+++ b/cornucopia.owasp.org/svelte.config.js
@@ -93,7 +93,26 @@ export default {
'/api/cre/webapp/pt_pt',
'/api/cre/webapp/pt_br',
'/api/cre/webapp/no_nb',
- '/api/cre/mobileapp/en'
+ '/api/cre/mobileapp/en',
+ '/card/mobileapp/PC2/1.1/en',
+ '/card/webapp/VE2/2.2/es',
+ '/card/webapp/VE2/2.2/it',
+ '/card/webapp/VE2/2.2/nl',
+ '/card/webapp/VE2/2.2/fr',
+ '/card/webapp/VE2/2.2/pt_pt',
+ '/card/webapp/VE2/2.2/pt_br',
+ '/card/webapp/VE2/2.2/no_nb',
+ '/card/webapp/VE2/2.2/ru',
+ '/card/webapp/VE2/3.0',
+ '/card/webapp/VE2/3.0/en',
+ '/card/webapp/VE2/3.0/es',
+ '/card/webapp/VE2/3.0/it',
+ '/card/webapp/VE2/3.0/nl',
+ '/card/webapp/VE2/3.0/fr',
+ '/card/webapp/VE2/3.0/pt_pt',
+ '/card/webapp/VE2/3.0/pt_br',
+ '/card/webapp/VE2/3.0/no_nb',
+ '/card/webapp/VE2/3.0/ru',
]
},
csrf: {
diff --git a/source/mobileapp-mappings-1.1.yaml b/source/mobileapp-mappings-1.1.yaml
index de423d99b..e0f74ec6f 100644
--- a/source/mobileapp-mappings-1.1.yaml
+++ b/source/mobileapp-mappings-1.1.yaml
@@ -6,7 +6,7 @@ meta:
version: "1.1"
layouts: ["cards", "leaflet"]
templates: ["bridge_qr", "bridge", "tarot", "tarot_qr"]
- languages: ["en"]
+ languages: ["en", "ru"]
suits:
-
id: "PC"
@@ -655,4 +655,24 @@ suits:
owasp_masvs: [ "-" ]
owasp_mastg: [ "-" ]
capec: [ "-" ]
+ safecode: [ "-" ]
+-
+ id: "WC"
+ name: "WILD CARD"
+ cards:
+ -
+ id: "JOAM"
+ value: "A"
+ url: "https://cornucopia.owasp.org/cards/JOAM"
+ owasp_masvs: [ "-" ]
+ owasp_mastg: [ "-" ]
+ capec: [ "-" ]
+ safecode: [ "-" ]
+ -
+ id: "JOBM"
+ value: "A"
+ url: "https://cornucopia.owasp.org/cards/JOBM"
+ owasp_masvs: [ "-" ]
+ owasp_mastg: [ "-" ]
+ capec: [ "-" ]
safecode: [ "-" ]
\ No newline at end of file
diff --git a/source/webapp-mappings-2.2.yaml b/source/webapp-mappings-2.2.yaml
index 6dc55c669..0aa82efb1 100644
--- a/source/webapp-mappings-2.2.yaml
+++ b/source/webapp-mappings-2.2.yaml
@@ -1298,3 +1298,31 @@ suits:
owasp_appsensor: [ "-" ]
capec: [ "-" ]
safecode: [ "-" ]
+-
+ id: "WC"
+ name: "WILD CARD"
+ cards:
+ -
+ id: "JOA"
+ value: "A"
+ url: "https://cornucopia.owasp.org/cards/JOA"
+ stride: []
+ stride_print: [ ]
+ owasp_dev_guide: [ "-" ]
+ owasp_dev_guide_print: [ "-" ]
+ owasp_asvs: [ "-" ]
+ owasp_asvs_print: [ "-" ]
+ capec: [ 184, 242, 248, 441, 444, 523, 549, 636, 691 ]
+ safecode: [ "-" ]
+ -
+ id: "JOB"
+ value: "B"
+ url: "https://cornucopia.owasp.org/cards/JOB"
+ stride: []
+ stride_print: [ ]
+ owasp_dev_guide: [ "-" ]
+ owasp_dev_guide_print: [ "-" ]
+ owasp_asvs: [ "-" ]
+ owasp_asvs_print: [ "-" ]
+ capec: [ 184, 242, 416, 438, 441, 444, 523, 518, 519, 548, 636, 691 ]
+ safecode: [ "-" ]
\ No newline at end of file
diff --git a/source/webapp-mappings-3.0.yaml b/source/webapp-mappings-3.0.yaml
index a45686236..fb735ff95 100644
--- a/source/webapp-mappings-3.0.yaml
+++ b/source/webapp-mappings-3.0.yaml
@@ -1880,12 +1880,12 @@ suits:
stride_print: [ 'Information Disclosure' ]
owasp_dev_guide: [ SC1, SC2, SC3, SC4, SC5, SC6, SC7, SC8, SC9, SC10, SC11, SC12, SC13, SFL1, SFL2, SFL14, SFL15, SDC2, SDC3, SDC4, SDC5, SDC6, SDA1, PDT1, PDT2, PDT3, PDT4, PDT5, PDT6, PDT7, PDT8, PDT9, PDT10, PDT11 ]
owasp_dev_guide_print: [ SC1-13, SFL1-2, SFL14-15, SDC2-6, SDA1, PDT1-11 ]
- owasp_asvs: [ 12.1.1, 12.1.2, 12.1.3, 12.1.4, 12.1.5, 12.2.1, 12.2.2, 12.3.1, 12.3.2, 12.3.3, 12.3.4, 12.3.5, 13.2.1, 13.2.2, 13.2.3, 13.3.1, 13.3.2, 13.3.3, 13.3.4, 13.3.5, 13.4.1, 13.4.2, 13.4.3, 13.4.4, 13.4.5, 13.4.6, 13.4.7, 15.1.1, 15.1.2, 15.2.1, 15.2.4, 16.3.3, 16.3.4 ]
- owasp_asvs_print: [ 12.1.1-5, 12.2.1-2, 12.3.1-5, 13.2.1-3, 13.3.1-5, 13.4.1-7, 15.1.1-2, 15.2.1, 15.2.4, 16.3.3-4 ]
+ owasp_asvs: [ 12.1.1, 12.1.2, 12.1.3, 12.1.4, 12.1.5, 12.2.1, 12.2.2, 12.3.1, 12.3.2, 12.3.3, 12.3.4, 12.3.5, 13.2.1, 13.2.2, 13.2.3, 13.3.1, 13.3.2, 13.3.3, 13.3.4, 13.4.1, 13.4.2, 13.4.3, 13.4.4, 13.4.5, 13.4.6, 13.4.7, 15.1.1, 15.1.2, 15.2.1, 15.2.4, 16.3.3, 16.3.4 ]
+ owasp_asvs_print: [ 12.1.1-5, 12.2.1-2, 12.3.1-5, 13.2.1-3, 13.3.1-4, 13.4.1-7, 15.1.1-2, 15.2.1, 15.2.4, 16.3.3-4 ]
capec: [ 37, 121, 159, 169, 217, 220, 310, 446 ]
capec_map:
37:
- owasp_asvs: [ 13.2.1, 13.2.2, 13.2.3, 13.3.1, 13.3.2, 13.3.3, 13.3.4, 13.3.5, 13.4.1, 13.4.7 ]
+ owasp_asvs: [ 13.2.1, 13.2.2, 13.2.3, 13.3.1, 13.3.2, 13.3.3, 13.3.4, 13.4.1, 13.4.7 ]
121:
owasp_asvs: [ 13.4.2 ]
169: