Add encrypt and decrypt endpoint and replaced encryption/decryption in app to use these endpoints

This commit is contained in:
austinkelsay 2024-09-17 16:00:00 -05:00
parent b800ab3b88
commit 09e0ba026a
11 changed files with 163 additions and 45 deletions

View File

@ -16,6 +16,7 @@ import { useToast } from '@/hooks/useToast';
import { formatDateTime } from '@/utils/time'; import { formatDateTime } from '@/utils/time';
import { validateEvent } from '@/utils/nostr'; import { validateEvent } from '@/utils/nostr';
import appConfig from "@/config/appConfig"; import appConfig from "@/config/appConfig";
import { useEncryptContent } from '@/hooks/encryption/useEncryptContent';
import 'primeicons/primeicons.css'; import 'primeicons/primeicons.css';
const MDDisplay = dynamic( const MDDisplay = dynamic(
@ -30,6 +31,8 @@ export default function DraftCourseDetails({ processedEvent, draftId, lessons })
const [user, setUser] = useState(null); const [user, setUser] = useState(null);
const [processedLessons, setProcessedLessons] = useState([]); const [processedLessons, setProcessedLessons] = useState([]);
const hasRunEffect = useRef(false); const hasRunEffect = useRef(false);
const { encryptContent, isLoading: encryptLoading, error: encryptError } = useEncryptContent();
const { showToast } = useToast(); const { showToast } = useToast();
const { returnImageProxy } = useImageProxy(); const { returnImageProxy } = useImageProxy();
@ -254,8 +257,7 @@ export default function DraftCourseDetails({ processedEvent, draftId, lessons })
switch (draft?.type) { switch (draft?.type) {
case 'document': case 'document':
if (draft?.price) { if (draft?.price) {
// encrypt the content with NEXT_PUBLIC_APP_PRIV_KEY to NEXT_PUBLIC_APP_PUBLIC_KEY encryptedContent = await encryptContent(draft.content);
encryptedContent = await nip04.encrypt(process.env.NEXT_PUBLIC_APP_PRIV_KEY, process.env.NEXT_PUBLIC_APP_PUBLIC_KEY, draft.content);
} }
event.kind = draft?.price ? 30402 : 30023; // Determine kind based on if price is present event.kind = draft?.price ? 30402 : 30023; // Determine kind based on if price is present
@ -277,8 +279,7 @@ export default function DraftCourseDetails({ processedEvent, draftId, lessons })
break; break;
case 'video': case 'video':
if (draft?.price) { if (draft?.price) {
// encrypt the content with NEXT_PUBLIC_APP_PRIV_KEY to NEXT_PUBLIC_APP_PUBLIC_KEY encryptedContent = await encryptContent(draft.content);
encryptedContent = await nip04.encrypt(process.env.NEXT_PUBLIC_APP_PRIV_KEY, process.env.NEXT_PUBLIC_APP_PUBLIC_KEY, draft.content);
} }
event.kind = draft?.price ? 30402 : 30023; event.kind = draft?.price ? 30402 : 30023;

View File

@ -47,18 +47,10 @@ const VideoLesson = ({ lesson, course, decryptionPerformed, isPaid }) => {
if (isPaid && decryptionPerformed) { if (isPaid && decryptionPerformed) {
return ( return (
<> <>
<div className="w-full aspect-video rounded-lg mb-4">
{/* Add your video player component here */}
<video controls className="w-full h-full">
<source src={lesson.videoUrl} type="video/mp4" />
Your browser does not support the video tag.
</video>
</div>
<MDDisplay className='p-4 rounded-lg w-full' source={lesson.content} /> <MDDisplay className='p-4 rounded-lg w-full' source={lesson.content} />
</> </>
); );
} } else if (isPaid && !decryptionPerformed) {
if (isPaid && !decryptionPerformed) {
return ( return (
<div className="w-full aspect-video rounded-lg flex flex-col items-center justify-center relative overflow-hidden"> <div className="w-full aspect-video rounded-lg flex flex-col items-center justify-center relative overflow-hidden">
<div <div
@ -78,8 +70,7 @@ const VideoLesson = ({ lesson, course, decryptionPerformed, isPaid }) => {
</p> </p>
</div> </div>
); );
} } else if (lesson?.content) {
if (lesson?.content) {
return <MDDisplay className='p-4 rounded-lg w-full' source={lesson.content} />; return <MDDisplay className='p-4 rounded-lg w-full' source={lesson.content} />;
} }
return null; return null;

View File

@ -11,6 +11,8 @@ import { useToast } from "@/hooks/useToast";
import { useNDKContext } from "@/context/NDKContext"; import { useNDKContext } from "@/context/NDKContext";
import { NDKEvent } from "@nostr-dev-kit/ndk"; import { NDKEvent } from "@nostr-dev-kit/ndk";
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { useEncryptContent } from '@/hooks/encryption/useEncryptContent';
const MDEditor = dynamic( const MDEditor = dynamic(
() => import("@uiw/react-md-editor"), () => import("@uiw/react-md-editor"),
{ {
@ -32,6 +34,7 @@ const DocumentForm = ({ draft = null, isPublished = false }) => {
const [content, setContent] = useState(draft?.content || ''); const [content, setContent] = useState(draft?.content || '');
const [user, setUser] = useState(null); const [user, setUser] = useState(null);
const [additionalLinks, setAdditionalLinks] = useState(draft?.additionalLinks || ['']); const [additionalLinks, setAdditionalLinks] = useState(draft?.additionalLinks || ['']);
const { encryptContent, isLoading: encryptLoading, error: encryptError } = useEncryptContent();
const { data: session, status } = useSession(); const { data: session, status } = useSession();
const { showToast } = useToast(); const { showToast } = useToast();
@ -72,8 +75,7 @@ const DocumentForm = ({ draft = null, isPublished = false }) => {
let encryptedContent; let encryptedContent;
if (draft?.price) { if (draft?.price) {
// encrypt the content with NEXT_PUBLIC_APP_PRIV_KEY to NEXT_PUBLIC_APP_PUBLIC_KEY encryptedContent = await encryptContent(draft.content);
encryptedContent = await nip04.encrypt(process.env.NEXT_PUBLIC_APP_PRIV_KEY, process.env.NEXT_PUBLIC_APP_PUBLIC_KEY, draft.content);
} }
event.kind = draft?.price ? 30402 : 30023; // Determine kind based on if price is present event.kind = draft?.price ? 30402 : 30023; // Determine kind based on if price is present

View File

@ -9,6 +9,8 @@ import { useToast } from "@/hooks/useToast";
import { useNDKContext } from "@/context/NDKContext"; import { useNDKContext } from "@/context/NDKContext";
import { NDKEvent } from "@nostr-dev-kit/ndk"; import { NDKEvent } from "@nostr-dev-kit/ndk";
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { useEncryptContent } from '@/hooks/encryption/useEncryptContent';
const MDEditor = dynamic( const MDEditor = dynamic(
() => import("@uiw/react-md-editor"), () => import("@uiw/react-md-editor"),
{ {
@ -29,7 +31,7 @@ const EmbeddedDocumentForm = ({ draft = null, isPublished = false, onSave, isPai
const [content, setContent] = useState(draft?.content || ''); const [content, setContent] = useState(draft?.content || '');
const [user, setUser] = useState(null); const [user, setUser] = useState(null);
const [additionalLinks, setAdditionalLinks] = useState(draft?.additionalLinks || ['']); const [additionalLinks, setAdditionalLinks] = useState(draft?.additionalLinks || ['']);
const { encryptContent, isLoading: encryptLoading, error: encryptError } = useEncryptContent();
const { data: session, status } = useSession(); const { data: session, status } = useSession();
const { showToast } = useToast(); const { showToast } = useToast();
const { ndk, addSigner } = useNDKContext(); const { ndk, addSigner } = useNDKContext();
@ -69,8 +71,7 @@ const EmbeddedDocumentForm = ({ draft = null, isPublished = false, onSave, isPai
let encryptedContent; let encryptedContent;
if (draft?.price) { if (draft?.price) {
// encrypt the content with NEXT_PUBLIC_APP_PRIV_KEY to NEXT_PUBLIC_APP_PUBLIC_KEY encryptedContent = await encryptContent(draft.content);
encryptedContent = await nip04.encrypt(process.env.NEXT_PUBLIC_APP_PRIV_KEY, process.env.NEXT_PUBLIC_APP_PUBLIC_KEY, draft.content);
} }
event.kind = draft?.price ? 30402 : 30023; // Determine kind based on if price is present event.kind = draft?.price ? 30402 : 30023; // Determine kind based on if price is present

View File

@ -0,0 +1,31 @@
import { useState } from 'react';
import axios from 'axios';
export const useDecryptContent = () => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const decryptContent = async (encryptedContent) => {
setIsLoading(true);
setError(null);
try {
const response = await axios.post('/api/decrypt', { encryptedContent });
console.log('response', response);
if (response.status !== 200) {
throw new Error('Failed to decrypt content');
}
const decryptedContent = response.data.decryptedContent;
setIsLoading(false);
return decryptedContent;
} catch (err) {
setError(err.message);
setIsLoading(false);
return null;
}
};
return { decryptContent, isLoading, error };
};

View File

@ -0,0 +1,30 @@
import { useState } from 'react';
import axios from 'axios';
export const useEncryptContent = () => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const encryptContent = async (content) => {
setIsLoading(true);
setError(null);
try {
const response = await axios.post('/api/encrypt', { content });
if (response.status !== 200) {
throw new Error('Failed to encrypt content');
}
const encryptedContent = response.data.encryptedContent;
setIsLoading(false);
return encryptedContent;
} catch (err) {
setError(err.message);
setIsLoading(false);
return null;
}
}
return { encryptContent, isLoading, error };
};

28
src/pages/api/decrypt.js Normal file
View File

@ -0,0 +1,28 @@
import { nip04 } from 'nostr-tools';
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method Not Allowed' });
}
const { encryptedContent } = req.body;
if (!encryptedContent) {
return res.status(400).json({ error: 'Encrypted content is required' });
}
const APP_PRIV_KEY = process.env.APP_PRIV_KEY;
const APP_PUBLIC_KEY = process.env.APP_PUBLIC_KEY;
if (!APP_PRIV_KEY || !APP_PUBLIC_KEY) {
return res.status(500).json({ error: 'Server configuration error' });
}
try {
const decryptedContent = await nip04.decrypt(APP_PRIV_KEY, APP_PUBLIC_KEY, encryptedContent);
res.status(200).json({ decryptedContent });
} catch (error) {
console.error('Decryption error:', error);
res.status(500).json({ error: 'Failed to decrypt content' });
}
}

28
src/pages/api/encrypt.js Normal file
View File

@ -0,0 +1,28 @@
import { nip04 } from 'nostr-tools';
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method Not Allowed' });
}
const { content } = req.body;
if (!content) {
return res.status(400).json({ error: 'Content is required' });
}
const APP_PRIV_KEY = process.env.APP_PRIV_KEY;
const APP_PUBLIC_KEY = process.env.APP_PUBLIC_KEY;
if (!APP_PRIV_KEY || !APP_PUBLIC_KEY) {
return res.status(500).json({ error: 'Server configuration error' });
}
try {
const encryptedContent = await nip04.encrypt(APP_PRIV_KEY, APP_PUBLIC_KEY, content);
res.status(200).json({ encryptedContent });
} catch (error) {
console.error('Encryption error:', error);
res.status(500).json({ error: 'Failed to encrypt content' });
}
}

View File

@ -10,6 +10,7 @@ import { useSession } from 'next-auth/react';
import { nip04, nip19 } from 'nostr-tools'; import { nip04, nip19 } from 'nostr-tools';
import { ProgressSpinner } from 'primereact/progressspinner'; import { ProgressSpinner } from 'primereact/progressspinner';
import { Accordion, AccordionTab } from 'primereact/accordion'; import { Accordion, AccordionTab } from 'primereact/accordion';
import { useDecryptContent } from "@/hooks/encryption/useDecryptContent";
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
const MDDisplay = dynamic(() => import("@uiw/react-markdown-preview"), { ssr: false }); const MDDisplay = dynamic(() => import("@uiw/react-markdown-preview"), { ssr: false });
@ -70,7 +71,14 @@ const useLessons = (ndk, fetchAuthor, lessonIds, pubkey) => {
if (event) { if (event) {
const author = await fetchAuthor(event.pubkey); const author = await fetchAuthor(event.pubkey);
const parsedLesson = { ...parseEvent(event), author }; const parsedLesson = { ...parseEvent(event), author };
setLessons(prev => [...prev, parsedLesson]); setLessons(prev => {
// Check if the lesson already exists in the array
const exists = prev.some(lesson => lesson.id === parsedLesson.id);
if (!exists) {
return [...prev, parsedLesson];
}
return prev;
});
} }
} catch (error) { } catch (error) {
console.error('Error fetching event:', error); console.error('Error fetching event:', error);
@ -78,11 +86,10 @@ const useLessons = (ndk, fetchAuthor, lessonIds, pubkey) => {
}; };
lessonIds.forEach(lessonId => fetchLesson(lessonId)); lessonIds.forEach(lessonId => fetchLesson(lessonId));
} }
}, [lessonIds, ndk, fetchAuthor]); }, [lessonIds, ndk, fetchAuthor, pubkey]);
useEffect(() => { useEffect(() => {
const uniqueLessonSet = new Set(lessons.map(JSON.stringify)); const newUniqueLessons = Array.from(new Map(lessons.map(lesson => [lesson.id, lesson])).values());
const newUniqueLessons = Array.from(uniqueLessonSet).map(JSON.parse);
setUniqueLessons(newUniqueLessons); setUniqueLessons(newUniqueLessons);
}, [lessons]); }, [lessons]);
@ -96,11 +103,10 @@ const useLessons = (ndk, fetchAuthor, lessonIds, pubkey) => {
const useDecryption = (session, paidCourse, course, lessons, setLessons) => { const useDecryption = (session, paidCourse, course, lessons, setLessons) => {
const [decryptionPerformed, setDecryptionPerformed] = useState(false); const [decryptionPerformed, setDecryptionPerformed] = useState(false);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const privkey = process.env.NEXT_PUBLIC_APP_PRIV_KEY; const { decryptContent } = useDecryptContent();
const pubkey = process.env.NEXT_PUBLIC_APP_PUBLIC_KEY;
useEffect(() => { useEffect(() => {
const decryptContent = async () => { const decrypt = async () => {
if (session?.user && paidCourse && !decryptionPerformed) { if (session?.user && paidCourse && !decryptionPerformed) {
setLoading(true); setLoading(true);
const canAccess = const canAccess =
@ -111,7 +117,7 @@ const useDecryption = (session, paidCourse, course, lessons, setLessons) => {
if (canAccess && lessons.length > 0) { if (canAccess && lessons.length > 0) {
try { try {
const decryptedLessons = await Promise.all(lessons.map(async (lesson) => { const decryptedLessons = await Promise.all(lessons.map(async (lesson) => {
const decryptedContent = await nip04.decrypt(privkey, pubkey, lesson.content); const decryptedContent = await decryptContent(lesson.content);
return { ...lesson, content: decryptedContent }; return { ...lesson, content: decryptedContent };
})); }));
setLessons(decryptedLessons); setLessons(decryptedLessons);
@ -124,8 +130,8 @@ const useDecryption = (session, paidCourse, course, lessons, setLessons) => {
} }
setLoading(false); setLoading(false);
} }
decryptContent(); decrypt();
}, [session, paidCourse, course, lessons, privkey, pubkey, decryptionPerformed, setLessons]); }, [session, paidCourse, course, lessons, decryptionPerformed, setLessons]);
return { decryptionPerformed, loading }; return { decryptionPerformed, loading };
}; };

View File

@ -10,11 +10,10 @@ import VideoDetails from '@/components/content/videos/VideoDetails';
import DocumentDetails from '@/components/content/documents/DocumentDetails'; import DocumentDetails from '@/components/content/documents/DocumentDetails';
import { ProgressSpinner } from 'primereact/progressspinner'; import { ProgressSpinner } from 'primereact/progressspinner';
import appConfig from "@/config/appConfig"; import appConfig from "@/config/appConfig";
import { useDecryptContent } from '@/hooks/encryption/useDecryptContent';
import { useEncryptContent } from '@/hooks/encryption/useEncryptContent';
import 'primeicons/primeicons.css'; import 'primeicons/primeicons.css';
const privkey = process.env.NEXT_PUBLIC_APP_PRIV_KEY;
const pubkey = process.env.NEXT_PUBLIC_APP_PUBLIC_KEY;
export default function Details() { export default function Details() {
const [event, setEvent] = useState(null); const [event, setEvent] = useState(null);
const [processedEvent, setProcessedEvent] = useState({}); const [processedEvent, setProcessedEvent] = useState({});
@ -29,6 +28,8 @@ export default function Details() {
const { ndk, addSigner } = useNDKContext(); const { ndk, addSigner } = useNDKContext();
const { data: session, update } = useSession(); const { data: session, update } = useSession();
const [user, setUser] = useState(null); const [user, setUser] = useState(null);
const { decryptContent } = useDecryptContent();
const { encryptContent } = useEncryptContent();
const { showToast } = useToast(); const { showToast } = useToast();
const router = useRouter(); const router = useRouter();
@ -46,23 +47,23 @@ export default function Details() {
}, [processedEvent]); }, [processedEvent]);
useEffect(() => { useEffect(() => {
const decryptContent = async () => { const decrypt = async () => {
if (paidResource && processedEvent.content) { if (paidResource && processedEvent.content) {
// Check if user is subscribed first // Check if user is subscribed first
if (user?.role?.subscribed) { if (user?.role?.subscribed) {
const decryptedContent = await nip04.decrypt(privkey, pubkey, processedEvent.content); const decryptedContent = await decryptContent(processedEvent.content);
setDecryptedContent(decryptedContent); setDecryptedContent(decryptedContent);
} }
// If not subscribed, check if they have purchased // If not subscribed, check if they have purchased
else if (user?.purchased?.some(purchase => purchase.resourceId === processedEvent.d)) { else if (user?.purchased?.some(purchase => purchase.resourceId === processedEvent.d)) {
const decryptedContent = await nip04.decrypt(privkey, pubkey, processedEvent.content); const decryptedContent = await decryptContent(processedEvent.content);
setDecryptedContent(decryptedContent); setDecryptedContent(decryptedContent);
} }
// If neither subscribed nor purchased, decryptedContent remains null // If neither subscribed nor purchased, decryptedContent remains null
} }
}; };
decryptContent(); decrypt();
}, [user, paidResource, processedEvent]); }, [user, paidResource, processedEvent]);
useEffect(() => { useEffect(() => {
@ -99,7 +100,7 @@ export default function Details() {
if (user && user.pubkey === event.pubkey) { if (user && user.pubkey === event.pubkey) {
setAuthorView(true); setAuthorView(true);
if (event.kind === 30402) { if (event.kind === 30402) {
const decryptedContent = await nip04.decrypt(privkey, pubkey, event.content); const decryptedContent = await decryptContent(event.content);
setDecryptedContent(decryptedContent); setDecryptedContent(decryptedContent);
} }
} }

View File

@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import axios from 'axios'; import axios from 'axios';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { hexToNpub } from '@/utils/nostr'; import { hexToNpub } from '@/utils/nostr';
import { nip19, nip04 } from 'nostr-tools'; import { nip19 } from 'nostr-tools';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { useSession } from 'next-auth/react'; import { useSession } from 'next-auth/react';
import { useImageProxy } from '@/hooks/useImageProxy'; import { useImageProxy } from '@/hooks/useImageProxy';
@ -19,6 +19,7 @@ import dynamic from 'next/dynamic';
import { validateEvent } from '@/utils/nostr'; import { validateEvent } from '@/utils/nostr';
import appConfig from "@/config/appConfig"; import appConfig from "@/config/appConfig";
import { useIsAdmin } from "@/hooks/useIsAdmin"; import { useIsAdmin } from "@/hooks/useIsAdmin";
import { useEncryptContent } from '@/hooks/encryption/useEncryptContent';
const MDDisplay = dynamic( const MDDisplay = dynamic(
() => import("@uiw/react-markdown-preview"), () => import("@uiw/react-markdown-preview"),
@ -33,12 +34,12 @@ export default function Draft() {
const { data: session, status } = useSession(); const { data: session, status } = useSession();
const [user, setUser] = useState(null); const [user, setUser] = useState(null);
const [nAddress, setNAddress] = useState(null); const [nAddress, setNAddress] = useState(null);
const [videoId, setVideoId] = useState(null);
const { width, height } = useResponsiveImageDimensions(); const { width, height } = useResponsiveImageDimensions();
const router = useRouter(); const router = useRouter();
const { showToast } = useToast(); const { showToast } = useToast();
const { ndk, addSigner } = useNDKContext(); const { ndk, addSigner } = useNDKContext();
const { isAdmin, isLoading } = useIsAdmin(); const { isAdmin, isLoading } = useIsAdmin();
const { encryptContent } = useEncryptContent();
useEffect(() => { useEffect(() => {
if (isLoading) return; if (isLoading) return;
@ -190,8 +191,7 @@ export default function Draft() {
switch (draft?.type) { switch (draft?.type) {
case 'document': case 'document':
if (draft?.price) { if (draft?.price) {
// encrypt the content with NEXT_PUBLIC_APP_PRIV_KEY to NEXT_PUBLIC_APP_PUBLIC_KEY encryptedContent = await encryptContent(draft.content);
encryptedContent = await nip04.encrypt(process.env.NEXT_PUBLIC_APP_PRIV_KEY, process.env.NEXT_PUBLIC_APP_PUBLIC_KEY, draft.content);
} }
event.kind = draft?.price ? 30402 : 30023; // Determine kind based on if price is present event.kind = draft?.price ? 30402 : 30023; // Determine kind based on if price is present
@ -213,8 +213,7 @@ export default function Draft() {
break; break;
case 'video': case 'video':
if (draft?.price) { if (draft?.price) {
// encrypt the content with NEXT_PUBLIC_APP_PRIV_KEY to NEXT_PUBLIC_APP_PUBLIC_KEY encryptedContent = await encryptContent(draft.content);
encryptedContent = await nip04.encrypt(process.env.NEXT_PUBLIC_APP_PRIV_KEY, process.env.NEXT_PUBLIC_APP_PUBLIC_KEY, draft.content);
} }
if (draft?.content.includes('.mp4') || draft?.content.includes('.mov') || draft?.content.includes('.avi') || draft?.content.includes('.wmv') || draft?.content.includes('.flv') || draft?.content.includes('.webm')) { if (draft?.content.includes('.mp4') || draft?.content.includes('.mov') || draft?.content.includes('.avi') || draft?.content.includes('.wmv') || draft?.content.includes('.flv') || draft?.content.includes('.webm')) {
@ -224,7 +223,7 @@ export default function Draft() {
const baseUrl = process.env.NEXT_PUBLIC_API_URL || "http://localhost:3000" const baseUrl = process.env.NEXT_PUBLIC_API_URL || "http://localhost:3000"
const videoEmbed = `<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;max-width:100%;"><video src="${baseUrl}/api/get-video-url?videoKey=${encodeURIComponent(extractedVideoId)}" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;" controls></video></div>`; const videoEmbed = `<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;max-width:100%;"><video src="${baseUrl}/api/get-video-url?videoKey=${encodeURIComponent(extractedVideoId)}" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;" controls></video></div>`;
if (draft?.price) { if (draft?.price) {
const encryptedVideoUrl = await nip04.encrypt(process.env.NEXT_PUBLIC_APP_PRIV_KEY, process.env.NEXT_PUBLIC_APP_PUBLIC_KEY, videoEmbed); const encryptedVideoUrl = await encryptContent(videoEmbed);
draft.content = encryptedVideoUrl; draft.content = encryptedVideoUrl;
} else { } else {
draft.content = videoEmbed; draft.content = videoEmbed;