@decido/shell-auth 1.0.0 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/index.mjs +1 -0
- package/package.json +15 -6
- package/src/index.ts +0 -131
- package/src/secureStorage.ts +0 -61
- package/tsconfig.json +0 -15
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# 🚀 @decido/shell-auth
|
|
2
|
+
|
|
3
|
+
> Decido OS Shell Authentication & Obfuscated Persistence Core
|
|
4
|
+
|
|
5
|
+
Bienvenido a la documentación oficial de **@decido/shell-auth**, un componente integral del ecosistema **Decido OS**.
|
|
6
|
+
|
|
7
|
+
## 📦 Instalación
|
|
8
|
+
|
|
9
|
+
Para aprovisionar este módulo dentro de otra área del monorepo o consumirlo remotamente:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @decido/shell-auth
|
|
13
|
+
# o mediante el gestor oficial del monorepo
|
|
14
|
+
pnpm add @decido/shell-auth
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 🔧 Estructura y Dependencias
|
|
18
|
+
|
|
19
|
+
Este paquete está diseñado para interoperar de forma nativa con la infraestructura central.
|
|
20
|
+
Para su correcto funcionamiento en un entorno aislado (Sandboxed), se apoya en los siguientes cimientos tecnológicos:
|
|
21
|
+
|
|
22
|
+
- `idb-keyval`
|
|
23
|
+
- `zustand`
|
|
24
|
+
- `@decido/tauri-bridge`
|
|
25
|
+
|
|
26
|
+
## 🔐 Licencia y Privacidad
|
|
27
|
+
El código de este componente se encuentra auditado y restringido (Sin Sourcemaps).
|
|
28
|
+
Propiedad Intelectual Protegida - Framework Decido OS.
|
|
29
|
+
Distribuido bajo licencia **UNLICENSED**.
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{create as S}from"zustand";import{persist as y,createJSONStorage as h}from"zustand/middleware";import{get as g,set as p,del as f}from"idb-keyval";import{secure as c}from"@decido/tauri-bridge";import{isTauri as u}from"@decido/tauri-bridge";var v=e=>typeof btoa>"u"?e:btoa(encodeURIComponent(e)),b=e=>{if(typeof atob>"u")return e;try{return decodeURIComponent(atob(e))}catch{return e}},d={getItem:async e=>{try{if(u()){let t=await c.secureVault.getItem(e);if(t!==null)return t}let r=await g(e);return r?b(r):null}catch(r){return console.error(`[SecureStorage] Failed to get item ${e}`,r),null}},setItem:async(e,r)=>{try{if(u()){await c.secureVault.setItem(e,r);return}let t=v(r);await p(e,t)}catch(t){console.error(`[SecureStorage] Failed to set item ${e}`,t)}},removeItem:async e=>{try{u()&&await c.secureVault.removeItem(e),await f(e)}catch(r){console.error(`[SecureStorage] Failed to remove item ${e}`,r)}}};var A=S()(y((e,r)=>({isAuthenticated:!1,userRole:null,userName:null,availableLicenses:[],activeContext:null,hasCompletedWelcome:!1,hasSeenTour:!1,login:(t,o,s)=>{let n=s||[{type:"personal",id:"personal",name:`${o}'s Private Space`}];e({isAuthenticated:!0,userRole:t,userName:o,availableLicenses:n,activeContext:n.length===1?n[0]:null})},joinSwarm:async t=>{try{let s=t.split(".")[1].replace(/-/g,"+").replace(/_/g,"/"),n=decodeURIComponent(atob(s).split("").map(function(l){return"%"+("00"+l.charCodeAt(0).toString(16)).slice(-2)}).join("")),a=JSON.parse(n);if(!a.tenantId||!a.name)return!1;let i={type:a.type||"enterprise",id:a.tenantId,name:a.name,swarmKey:a.swarm_key,websocketRelayUrl:a.ws_url},{availableLicenses:m}=r();return m.find(l=>l.id===i.id)?e({activeContext:i}):e({availableLicenses:[...m,i],activeContext:i}),!0}catch(o){return console.error("Failed to join swarm from token",o),!1}},setActiveContext:t=>{let{availableLicenses:o}=r(),s=o.find(n=>n.id===t)||null;e({activeContext:s})},setHasCompletedWelcome:t=>{e({hasCompletedWelcome:t})},setHasSeenTour:t=>{e({hasSeenTour:t})},logout:()=>e({isAuthenticated:!1,userRole:null,userName:null,availableLicenses:[],activeContext:null,hasCompletedWelcome:!1,hasSeenTour:!1})}),{name:"decido-auth-storage",storage:h(()=>d)}));export{d as secureStorage,A as useAuthStore};
|
package/package.json
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decido/shell-auth",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.2",
|
|
4
4
|
"description": "Decido OS Shell Authentication & Obfuscated Persistence Core",
|
|
5
|
-
"main": "
|
|
6
|
-
"types": "
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
7
|
"directories": {
|
|
8
8
|
"src": "src"
|
|
9
9
|
},
|
|
10
10
|
"exports": {
|
|
11
|
-
".":
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.mjs",
|
|
14
|
+
"require": "./dist/index.js",
|
|
15
|
+
"default": "./dist/index.mjs"
|
|
16
|
+
}
|
|
12
17
|
},
|
|
13
18
|
"dependencies": {
|
|
14
19
|
"idb-keyval": "^6.2.1",
|
|
15
20
|
"zustand": "^4.5.2",
|
|
16
|
-
"@decido/tauri-bridge": "0.
|
|
21
|
+
"@decido/tauri-bridge": "4.0.2"
|
|
17
22
|
},
|
|
18
23
|
"devDependencies": {
|
|
19
24
|
"typescript": "^5.0.0"
|
|
@@ -22,8 +27,12 @@
|
|
|
22
27
|
"access": "public"
|
|
23
28
|
},
|
|
24
29
|
"license": "UNLICENSED",
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
],
|
|
33
|
+
"module": "./dist/index.mjs",
|
|
25
34
|
"scripts": {
|
|
26
35
|
"lint": "eslint \"src/**/*.ts*\"",
|
|
27
|
-
"build": "tsup src/index.ts --format esm
|
|
36
|
+
"build": "tsup src/index.ts --format esm,cjs"
|
|
28
37
|
}
|
|
29
38
|
}
|
package/src/index.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { create } from 'zustand';
|
|
2
|
-
import { persist, createJSONStorage } from 'zustand/middleware';
|
|
3
|
-
import { secureStorage } from './secureStorage';
|
|
4
|
-
|
|
5
|
-
export type UserRole = 'creator' | 'admin' | 'user' | 'demo' | 'developer';
|
|
6
|
-
export type LicenseType = 'personal' | 'enterprise';
|
|
7
|
-
|
|
8
|
-
export interface LicenseTarget {
|
|
9
|
-
type: LicenseType;
|
|
10
|
-
id: string;
|
|
11
|
-
name: string;
|
|
12
|
-
enabledPlugins?: string[];
|
|
13
|
-
systemPrompt?: string;
|
|
14
|
-
swarmKey?: string;
|
|
15
|
-
websocketRelayUrl?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface AuthState {
|
|
19
|
-
isAuthenticated: boolean;
|
|
20
|
-
userRole: UserRole | null;
|
|
21
|
-
userName: string | null;
|
|
22
|
-
|
|
23
|
-
availableLicenses: LicenseTarget[];
|
|
24
|
-
activeContext: LicenseTarget | null;
|
|
25
|
-
hasCompletedWelcome: boolean;
|
|
26
|
-
hasSeenTour: boolean;
|
|
27
|
-
|
|
28
|
-
login: (role: UserRole, name: string, licenses?: LicenseTarget[]) => void;
|
|
29
|
-
joinSwarm: (token: string) => Promise<boolean>;
|
|
30
|
-
setActiveContext: (licenseId: string) => void;
|
|
31
|
-
setHasCompletedWelcome: (val: boolean) => void;
|
|
32
|
-
setHasSeenTour: (val: boolean) => void;
|
|
33
|
-
logout: () => void;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export const useAuthStore = create<AuthState>()(
|
|
37
|
-
persist(
|
|
38
|
-
(set, get) => ({
|
|
39
|
-
isAuthenticated: false,
|
|
40
|
-
userRole: null,
|
|
41
|
-
userName: null,
|
|
42
|
-
availableLicenses: [],
|
|
43
|
-
activeContext: null,
|
|
44
|
-
hasCompletedWelcome: false,
|
|
45
|
-
hasSeenTour: false,
|
|
46
|
-
|
|
47
|
-
login: (role, name, licenses) => {
|
|
48
|
-
const defaultLicenses: LicenseTarget[] = licenses || [{
|
|
49
|
-
type: 'personal',
|
|
50
|
-
id: 'personal',
|
|
51
|
-
name: `${name}'s Private Space`
|
|
52
|
-
}];
|
|
53
|
-
|
|
54
|
-
set({
|
|
55
|
-
isAuthenticated: true,
|
|
56
|
-
userRole: role,
|
|
57
|
-
userName: name,
|
|
58
|
-
availableLicenses: defaultLicenses,
|
|
59
|
-
activeContext: defaultLicenses.length === 1 ? defaultLicenses[0] : null
|
|
60
|
-
});
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
joinSwarm: async (token: string) => {
|
|
64
|
-
try {
|
|
65
|
-
const base64Url = token.split('.')[1];
|
|
66
|
-
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
|
67
|
-
const jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
|
|
68
|
-
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
|
69
|
-
}).join(''));
|
|
70
|
-
|
|
71
|
-
const payload = JSON.parse(jsonPayload);
|
|
72
|
-
|
|
73
|
-
if (!payload.tenantId || !payload.name) return false;
|
|
74
|
-
|
|
75
|
-
const newTarget: LicenseTarget = {
|
|
76
|
-
type: payload.type || 'enterprise',
|
|
77
|
-
id: payload.tenantId,
|
|
78
|
-
name: payload.name,
|
|
79
|
-
swarmKey: payload.swarm_key,
|
|
80
|
-
websocketRelayUrl: payload.ws_url
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const { availableLicenses } = get();
|
|
84
|
-
if (!availableLicenses.find(l => l.id === newTarget.id)) {
|
|
85
|
-
set({
|
|
86
|
-
availableLicenses: [...availableLicenses, newTarget],
|
|
87
|
-
activeContext: newTarget
|
|
88
|
-
});
|
|
89
|
-
} else {
|
|
90
|
-
set({ activeContext: newTarget });
|
|
91
|
-
}
|
|
92
|
-
return true;
|
|
93
|
-
} catch (e) {
|
|
94
|
-
console.error("Failed to join swarm from token", e);
|
|
95
|
-
return false;
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
|
|
99
|
-
setActiveContext: (licenseId: string) => {
|
|
100
|
-
const { availableLicenses } = get();
|
|
101
|
-
const target = availableLicenses.find(l => l.id === licenseId) || null;
|
|
102
|
-
set({ activeContext: target });
|
|
103
|
-
},
|
|
104
|
-
|
|
105
|
-
setHasCompletedWelcome: (val: boolean) => {
|
|
106
|
-
set({ hasCompletedWelcome: val });
|
|
107
|
-
},
|
|
108
|
-
|
|
109
|
-
setHasSeenTour: (val: boolean) => {
|
|
110
|
-
set({ hasSeenTour: val });
|
|
111
|
-
},
|
|
112
|
-
|
|
113
|
-
logout: () => set({
|
|
114
|
-
isAuthenticated: false,
|
|
115
|
-
userRole: null,
|
|
116
|
-
userName: null,
|
|
117
|
-
availableLicenses: [],
|
|
118
|
-
activeContext: null,
|
|
119
|
-
hasCompletedWelcome: false,
|
|
120
|
-
hasSeenTour: false
|
|
121
|
-
}),
|
|
122
|
-
}),
|
|
123
|
-
{
|
|
124
|
-
name: 'decido-auth-storage',
|
|
125
|
-
storage: createJSONStorage(() => secureStorage)
|
|
126
|
-
}
|
|
127
|
-
)
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
// Re-export secureStorage helper just in case it's needed externally
|
|
131
|
-
export * from './secureStorage';
|
package/src/secureStorage.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { get, set, del } from 'idb-keyval';
|
|
2
|
-
import { StateStorage } from 'zustand/middleware';
|
|
3
|
-
import { secure } from '@decido/tauri-bridge';
|
|
4
|
-
import { isTauri } from '@decido/tauri-bridge';
|
|
5
|
-
|
|
6
|
-
// Basic obfuscation wrapper for pure SSR/Web Fallback
|
|
7
|
-
const obfuscate = (data: string): string => {
|
|
8
|
-
if (typeof btoa === 'undefined') return data;
|
|
9
|
-
return btoa(encodeURIComponent(data));
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const deobfuscate = (data: string): string => {
|
|
13
|
-
if (typeof atob === 'undefined') return data;
|
|
14
|
-
try {
|
|
15
|
-
return decodeURIComponent(atob(data));
|
|
16
|
-
} catch {
|
|
17
|
-
return data;
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export const secureStorage: StateStorage = {
|
|
22
|
-
getItem: async (name: string): Promise<string | null> => {
|
|
23
|
-
try {
|
|
24
|
-
if (isTauri()) {
|
|
25
|
-
const val = await secure.secureVault.getItem(name);
|
|
26
|
-
if (val !== null) return val;
|
|
27
|
-
}
|
|
28
|
-
// WEB Fallback
|
|
29
|
-
const val = await get(name);
|
|
30
|
-
if (!val) return null;
|
|
31
|
-
return deobfuscate(val);
|
|
32
|
-
} catch (err) {
|
|
33
|
-
console.error(`[SecureStorage] Failed to get item ${name}`, err);
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
setItem: async (name: string, value: string): Promise<void> => {
|
|
38
|
-
try {
|
|
39
|
-
if (isTauri()) {
|
|
40
|
-
await secure.secureVault.setItem(name, value);
|
|
41
|
-
return; // Do not leak to indexedDB
|
|
42
|
-
}
|
|
43
|
-
// WEB Fallback
|
|
44
|
-
const obfuscated = obfuscate(value);
|
|
45
|
-
await set(name, obfuscated);
|
|
46
|
-
} catch (err) {
|
|
47
|
-
console.error(`[SecureStorage] Failed to set item ${name}`, err);
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
removeItem: async (name: string): Promise<void> => {
|
|
51
|
-
try {
|
|
52
|
-
if (isTauri()) {
|
|
53
|
-
await secure.secureVault.removeItem(name);
|
|
54
|
-
// Also clean legacy web fallback just in case
|
|
55
|
-
}
|
|
56
|
-
await del(name);
|
|
57
|
-
} catch (err) {
|
|
58
|
-
console.error(`[SecureStorage] Failed to remove item ${name}`, err);
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
};
|
package/tsconfig.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"strict": true,
|
|
5
|
-
"outDir": "dist",
|
|
6
|
-
"declaration": true,
|
|
7
|
-
"declarationMap": true,
|
|
8
|
-
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
9
|
-
"module": "ESNext",
|
|
10
|
-
"target": "ESNext",
|
|
11
|
-
"moduleResolution": "bundler"
|
|
12
|
-
},
|
|
13
|
-
"include": ["src/**/*"],
|
|
14
|
-
"exclude": ["node_modules", "dist"]
|
|
15
|
-
}
|