[컴] passkey 와 private key 의 차이

 

/ 개인키 / 공용키 / 암호 / 패스키 / 사용 / 보안 / security / secure / auth / authorization

passkey 와 private key 의 차이

패스키를 생성하는 것은 비밀번호를 만드는 것과 비슷하다.

password 에서 word 대신 key를 넣어서 만든 단어다. 즉, 이전에 어떤 단어word 를 이용했다면, 이젠 key 를 사용한단 이야기다.

우리가 site A 를 접속한다고 하면, 우리는 비밀번호를 넣고 login 을 하게 된다. 패스키를 사용하게 되면, 우리는 비번을 넣는 대신 private key 를 이용하게 된다.

ssh login 을 할 때 이미 많이 사용하던 방법이다. ssh login에서는 private key 내용이 저장된 파일을 지정해서 사용했다.(.pem)

이것이 패스키(passkey) 와 비슷하다고 볼 수 있다.

ssh login 에서도 비슷하지만, 패스키에서도 서버에 public key 가 저장돼 있게 된다. 그래서 private key(패스키도 private key이다)를 가지고 로그인을 할 수 있게 된다.

이 passkey는 각 웹사이트마다, 앱마다 다른 passkey를 생성하게 된다. 애플에서는 iCloud Keychain 에 이 passkey를 저장한다. 이 때 end-to-end encryption 을 하기에 누구도 알 수 없다고 이야기한다. [ref. 3] 그리고 이 passkey는 apple 기기에 동기화 된다.[ref. 4]

당연한 이야기겠지만, 그렇기에 웹사이트에서 패스키를 지원해야 한다.

그럼 이것이 이전의 private key 를 사용하는 것과 무엇이 다른가?

그것은 private key 의 생성과 보관에서 차이를 보인다.

생성

직접 생성할 필요가 없다. 웹사이트에서 passkey를 지원한다면, key를 생성하는 절차가 자동화 될 것이다. ref. 3 의 아이폰에서 passkey를 저장하는 시나리오를 보면 알겠지만, 계정이름을 적고 나면, passkey를 저장하기 위한 화면이 뜬다. 그 후 현재 아이폰에 저장하겠다고 선택하면 된다.

즉, passkey 는 당연히 누군가 생성해줬을 것이다. ref. 4에서 말하지만, os 가 app 또는 website 의 계정과 연관된 unique 한 암호화한 key pair 를 생성한다. 그리고 public key 는 서버에 저장되고, private key 는 local device 에 저장된다.

보관 및 사용

아이폰에 저장된 이후, 이 passkey 를 사용하기 위해서 touch ID 나 face ID 를 이용해서 authorize 한 이후(권한을 준 후), passkey 를 사용할 수 있게 된다. 그리고 이 passkey 는 app또는 website에 user를 authenticate(인증) 해준다.

Reference

  1. “비밀번호를 안전하고 편리하게 대체한다” 패스키의 이해 - ITWorld Korea, 2023-01-26
  2. [까다로운 IT] 애플∙구글∙MS 모두 도입하는 패스키, 비밀번호를 대체할 수 있을까? - Byline Network, 2022-06-17
  3. Sign in with passkeys on iPhone - Apple Support
  4. About the security of passkeys - Apple Support
  5. Google Online Security Blog: So long passwords, thanks for all the phish

[컴] nextjs commerce 에서 login 의 동작

nextjs commerce 에서 login 의 동작

login button click 시

  1. LoginView 에서 submit button 을 누르면, useLogin을 호출한다.
  2. useLogin 은 현재의 provider에서 auth.useLogin을 가져오고,
  3. useMutationHook 을 호출하면서 그것을 parameter hook 으로 보낸다.
  4. 그러면, useMutationHook에서 hook.useHook을 호출한다. 즉, provider.auth.useLogin.useHook 을 호출하게 되는 것이다.
  1. useHook은 다시 그 안에서, fetch 를 호출하는데, 이안에서 다시 useLogin.fetcher 를 호출하게 된다.
  2. useLogin.fetcher에서 mutation 을 보내게 된다.
// components/auth/LoginView.tsx
...

const LoginView: React.FC = () => {
  ...

  const login = useLogin()

  const handleLogin = async (e: React.SyntheticEvent<EventTarget>) => {
    ...

    try {
      setLoading(true)
      setMessage('')

      // --> packages/commerce/src/auth/use-login.tsx 
      await login({
        email,
        password,
      })
      ...
    } catch ({ errors }) {
      ...
    } finally {
      setLoading(false)
    }
  }

  ...

  return (
    <form
      onSubmit={handleLogin}
      className="w-80 flex flex-col justify-between p-3"
    >
      ...
    </form>
  )
}

export default LoginView
// packages/commerce/src/auth/use-login.tsx 

export type UseLogin<
  H extends MutationHook<LoginHook> = MutationHook<LoginHook>
> = ReturnType<H['useHook']>

export const fetcher: HookFetcherFn<LoginHook> = mutationFetcher

const fn = (provider: Provider) => provider.auth?.useLogin!

const useLogin: UseLogin = (...args) => {

  // --> packages/commerce/src/utils/use-hook.ts
  const hook = useHook(fn)

  // --> packages/commerce/src/utils/use-hook.ts
  return useMutationHook({ fetcher, ...hook })(...args)
}

export default useLogin
// packages/commerce/src/utils/use-hook.ts

export function useHook<
  P extends Provider,
  H extends MutationHook<any> | SWRHook<any>
>(fn: (provider: P) => H) {
  const { providerRef } = useCommerce<P>()
  const provider = providerRef.current
  return fn(provider)
}
...
export function useMutationHook<H extends MutationHook<any>>(
  hook: PickRequired<H, 'fetcher'>
) {
  const fetcher = useFetcher()

  // --> packages/vendure/src/auth/use-login.tsx
  return hook.useHook({

    fetch: useCallback(
      ({ input } = {}) => {

        // --> packages/vendure/src/auth/use-login.tsx
        return hook.fetcher({
          input,
          options: hook.fetchOptions,
          fetch: fetcher,
        })
      },
      [fetcher, hook.fetchOptions]
    ),
  })
}
// packages/vendure/src/auth/use-login.tsx

export default useLogin as UseLogin<typeof handler>

export const handler: MutationHook<LoginHook> = {
  ...
  async fetcher({ input: { email, password }, options, fetch }) {
    if (!(email && password)) {
      throw new CommerceError({
        message: 'A email and password are required to login',
      })
    }

    const variables: LoginMutationVariables = {
      username: email,
      password,
    }

    const { login } = await fetch<LoginMutation>({
      ...options,
      variables,
    })

    if (login.__typename !== 'CurrentUser') {
      throw new ValidationError(login)
    }

    return null
  },
  useHook:
    ({ fetch }) =>{
      return () => {
        const { mutate } = useCustomer()

        return useCallback(
          async function login(input) {

            // --> packages/commerce/src/utils/use-hook.ts
            const data = await fetch({ input })

            await mutate()
            return data
          },
          [fetch, mutate]
        )
      }
    },
}

아래와 같은 graphql 을 보내게 된다.

{"query":"
  mutation login($username: String!, $password: String!) {
    login(username: $username, password: $password) {
      __typename
      ... on CurrentUser {
        id
      }
      ... on ErrorResult {
        errorCode
        message
      }
    }
  }
  ","variables":{"username":"gaedduck@gmail.com","password":"ldldlldfgpassword"}}

See Also

  1. 쿠…sal: [컴][웹] next.js commerce + vendure 서버 실행

[컴 inline keyword 에 대한 설명

인라인 / inline /

inline keyword 에 대한 설명

jvm 에서의 inline

jvm 언어에서 작고, 반복적으로 사용되는 함수에 대해 inline keyword 을 넣을 필요는 없다. JVM JIT 이 알아서 해준다. inline 을 하는 것으로 이득을 볼 수 있다.[ref. 1]

c++ compiler 에서의 inline[ref. 3]

inline function 으로 만드는 것은 function call 에 대한 overhead 를 없애준다. 그런데 이 inline 으로 변경하는 것은 compiler 의 판단에 달려있다. inline keyword 를 넣어주면, 그나마 더 많은 경우에 compiler 가 함수를 inline 으로 만든다. 하지만 이 조차도, 특정한 경우에서는 inline 으로 만들지 않는다.(예를 들면, 재귀함수 같은 경우) 그러므로 inline 을 사용해서 함수를 inline 으로 만드는 것은 항상 그렇지 않으니, 주의해야 한다.

Reference

  1. Use inline keyword for small, private functions in kotlin? - Stack Overflow
  2. When Short Methods Pay Off: JIT Inlining - DZone
  3. Inline Functions (C++) | Microsoft Learn

[컴] vendure 의 storefront 구현

쇼핑몰 shopping mall / how to implement / vendure client

vendure 의 storefront 구현

다음 링크의 내용을 구현하면 된다.

최소 구현:

  1. navigation : 컬렉션 쿼리를 사용하여 컬렉션등을 기반으로 탐색(navigation)을 표시합니다.
  2. 제품 목록 : 검색 쿼리를 사용하면 컬렉션별로 필터링할 수 있으며 facet filtering도 구현할 수 있습니다.
  3. 상세페이지 : 변형 상품 선택 및 카트에 추가 기능이 포함된 ‘제품 세부 정보 화면’.
  4. 카트 화면 : 품목을 제거하거나 수량을 수정할 수 있는 카트 화면.
  5. checkout flow : 배송 주소 및 결제를 포함한 결제 흐름.
  6. login page : 비밀번호 분실 흐름 및 계정 생성 흐름이 있는 로그인 페이지
  7. 고객 계정 대시보드
  8. 고객 주문 내역
  9. 고객 비밀번호 재설정 플로우
  10. 고객 이메일 주소 변경 흐름

[컴][os] Windows 에서 symbolic link 만들기

 ln / 링크 /소프트 링크 /

junction 을 이용하면 된다.

mklink /j 

file link:

@REM symbolic link 생성
mklink a.exe C:\Windows\system32\notepad.exe


@REM symbolic link 삭제
del a.exe

directory link:

@REM 생성
mklink /d prog "C:\Program Files"


@REM symbolic link 삭제
rd prog

junction 생성

@REM junction 생성
mklink /j prog "C:\Program Files"

@REM junction 삭제
rd prog

mklikn 로 junction 도 만들 수 있다. 이 junction 은 예전부터 있던 기능이다. 기능상으로는 Symbolic link 가 더 많지만, security 이점때문에 junction 을 더 많이 사용한다고 한다.[ref. 3]

junction symbolic link
windows 2000 부터 가능 Vista 부터 가능
absolute path 만 가능 relative path 도 가능.
local computer 의 path 만 가능 local, remote, relative 등 모두 가능
file 에 대한 junction 은 만들 수 없다. file 에 대한 link 를 만들 수 있다.

Reference

  1. How can I create a symbolic link on Windows 10? - Super User
  2. MKLink - Windows CMD - SS64.com
  3. windows - What is the difference between NTFS Junction Points and Symbolic Links? - Stack Overflow

[컴][웹] vendure 의 Session 관리

vendure 의 Session 관리

cookie 또는 bearer token 을 사용한다.

이것은 VendureConfig 의 authOptions.tokenMethod property 에서 정의된다.

cookie 를 사용하는 것은 browser 기반의 app에서 사용하기 편하다. 브라우저가 cookie를 자동으로 관리해준다.

client에서 credential option 을 켜주면 된다.(credential: include 또는 withCredential: true)

server(Vendure server) 에서는 authOptions.cookieOptions.secret property 에 secret string 을 설정해줘야 한다. 그러면 서버는 이 secret key 로 cookie를 sign 해서 보내게 된다. 이 값은 환경변수로도 설정이 된다.

Bearer token

Bearer token은 받은 response 의 header 에서 token 을 읽고, 그것을 다시 request 할 때 header 에 넣고 쏘아야 한다.

특정 query 나 mutation들이 사용되면 session이 시작된다.

기본값적으로 이 token을 갖고있는 header 의 key 는 ‘vendure-auth-token’ 이다. 이 값은 authTokenHeaderKey 에서 변경할 수 있다.

  • client 는 매번 이 header 가 있는지를 확인
  • vendure-auth-token header 가 있으면, 그것을 읽어서 저장한다. 이 값이 bearer token 이다.
  • 이 bearer token 을 request 할 때마자 같이 실어 보낸다. Authorization: Bearer <token> 으로.

See Also

  1. 쿠…sal: [컴][웹] next.js commerce + vendure 서버 실행

[컴] fontconfig library 정보

 

폰트 / 라이브러리 / 리눅스 / 폰트컨피그

fontconfig library 정보

application 들이 가능한 font들의 list 를 제공하고, font 들이 어떻게 rendered 될지를 설정할 수 있게 해준다. Xorg 는 ’X’라고 알려졌는데, unix-like OS 에서 GUI 환경을 관리하는 display server 이다.