[에러 해결] Python NameError: name ‘generate_chk’ is not defined 원인과 해결 방법

작성자

카테고리:

[에러 해결] Python NameError: name ‘generate_chk’ is not defined 원인과 해결 방법

에러 상황 소개

Python 스크립트 실행 중 NameError: name 'generate_chk' is not defined 오류가 발생했습니다. 이 오류는 Geometry Dash 레벨 업로드 프로그램을 파이썬으로 개발하는 과정에서 seed2 값을 생성하기 위해 generate_chk 함수를 호출했으나, 해당 함수가 정의되지 않아 발생하는 전형적인 문제였습니다.

문제의 스크립트에서 발생한 에러 메시지는 다음과 같습니다:

[***@archlinux usernm]$ python upload
What is your username?levelnotinauto
What is your Account ID?38627839
What is your password?********
What is the Level name?Check Desc
How many coins are there?4848394
How many stars do you want?392084092849
Traceback (most recent call last):
  File "/home/***/scripts/usernm/upload", line 43, in <module>
    "seed2": generate_chk(key="41274", values=[generate_upload_seed(levelString)], salt="xI25fpAapCQg"), # This is talked about in the CHK encryption,
             ^^^^^^^^^^^^
NameError: name 'generate_chk' is not defined. Did you mean: 'generate_gjp2'?

발생 원인

NameError: name 'generate_chk' is not defined 오류는 파이썬 인터프리터가 generate_chk라는 이름의 함수를 찾을 수 없을 때 발생합니다. 문제의 스크립트에서는 requests, base64, hashlib 모듈을 임포트하고 있었지만, generate_chk 함수는 이들 표준 라이브러리에 포함되어 있지 않습니다. 또한, 사용자 본인이 해당 함수를 직접 정의하지도 않았습니다.

사용자는 특정 Geometry Dash API 문서(현재는 아카이브됨)에서 generate_chk(key="41274", values=[generate_upload_seed(levelString)], salt="xI25fpAapCQg")와 같은 함수 호출 방식을 확인했으나, 실제 함수의 구현 코드를 누락한 채 사용했습니다. 이는 마치 특정 요리법에 "특별 소스 추가"라고만 적혀있고, 그 특별 소스를 만드는 방법은 알려주지 않은 상황과 같습니다. 즉, 함수의 호출 방식만 알고 실제 구현이 없는 상태에서 호출했기 때문에 발생한 오류입니다.

특히 generate_chk 함수가 generate_upload_seed 함수의 반환 값을 인자로 받기 때문에, generate_upload_seed 함수 또한 정의되지 않았을 가능성이 높습니다.

추가적으로, 원본 코드에서 generate_gjp2 함수는 정의되었으나, 그 반환 값인 hash를 전역 변수로 할당하지 않아 data 딕셔너리에서 "gjp": hash 부분도 NameError를 일으킬 수 있는 잠재적인 문제가 있었습니다.

해결 방법 코드 예시

이 문제를 해결하려면 generate_chkgenerate_upload_seed 함수의 실제 구현 코드를 스크립트 내에 정의해야 합니다. Geometry Dash API와 관련된 커뮤니티나 다른 오픈소스 프로젝트를 통해 해당 함수들의 구현을 찾거나, API 문서의 내용을 바탕으로 직접 구현해야 할 수도 있습니다.

아래는 Geometry Dash API의 seed2 생성을 위한 generate_chkgenerate_upload_seed 함수의 예시 구현입니다. 실제 Geometry Dash API의 동작 방식에 따라 내부 로직이 달라질 수 있으므로, 참고하여 실제 API의 요구사항에 맞게 수정해야 합니다. (특히 XOR 연산 방식과 사용되는 상수 값들을 주의 깊게 확인해야 합니다.)

에러 코드 (Before)

# ... (생략) ...

data = {
    # ...
    "gjp": hash, # 'hash'가 정의되지 않았을 수 있음
    # ...
    "seed2": generate_chk(key="41274", values=[generate_upload_seed(levelString)], salt="xI25fpAapCQg"), # NameError 발생 지점
    "secret": "Wmfd2893gb7"
}

# ... (생략) ...

수정된 코드 예시 (After)

generate_upload_seedgenerate_chk 함수 정의를 추가하고, generate_gjp2 함수의 호출을 명확히 합니다.

import requests
import base64
import hashlib  # sha1() lives there

user = input("What is your username?")
accid = input("What is your Account ID?")
passwd = input("What is your password?")
lname = input ("What is the Level name?")
coin = input("How many coins are there?")
stars = input("How many stars do you want?")

# --- Geometry Dash API 관련 유틸리티 함수 정의 시작 ---
# 이 함수들은 Geometry Dash API의 특정 암호화 로직을 따르므로,
# 공식 문서 또는 다른 구현을 참고하여 정확성을 확인해야 합니다.

def generate_gjp2(password: str, salt: str = "mI29fmAnxgTs") -> str:
    password_with_salt = password + salt
    return hashlib.sha1(password_with_salt.encode()).hexdigest()

def generate_upload_seed(level_string: str) -> str:
    """
    Geometry Dash API의 레벨 업로드 시 사용되는 seed 값을 생성하는 예시 함수.
    실제 구현은 levelString을 특정 방식으로 처리(예: Base64 인코딩, XOR 연산 등)할 수 있습니다.
    여기서는 예시를 위해 levelString의 길이를 반환합니다.
    실제 GD API는 더 복잡한 로직을 가질 수 있으니, 필요시 정확한 구현을 찾아야 합니다.
    """
    return str(len(level_string)) # placeholder: 실제 로직으로 교체 필요

def generate_chk(key: str, values: list, salt: str) -> str:
    """
    Geometry Dash API의 "seed2" 값을 생성하는 예시 함수.
    일반적으로 key, values (generate_upload_seed의 결과), salt를 조합하여
    XOR 연산 및 SHA1 해싱을 통해 체크섬을 생성합니다.
    
    이 구현은 일반적인 Geometry Dash API 체크섬 패턴을 기반으로 한 예시입니다.
    정확한 알고리즘은 API 버전이나 엔드포인트에 따라 다를 수 있으므로,
    공식 문서 또는 역설계된 구현과 대조하여 검증하는 것이 필수적입니다.
    """
    if not values:
        raise ValueError("Values list cannot be empty for generate_chk.")
        
    main_value = str(values[0]) # values는 보통 단일 요소 리스트일 것
    
    # GD API 체크섬 로직의 일반적인 패턴 (XOR 연산 및 SHA1 해싱)
    
    # 1. key와 main_value를 조합
    # 예시 조합: seed + key
    combined_string_for_xor = main_value + key
    
    # 2. XOR 연산 적용 (GD API의 특정 방식)
    # 원본 문제의 seed2 salt 값을 XOR 키로 활용하는 경우가 많음
    xor_secret_key = "xI25fpAapCQg" # 원본 호출의 salt 값 재사용, 실제 GD API의 특정 값을 사용해야 함
    
    xor_result_chars = []
    for i, char_code in enumerate(combined_string_for_xor):
        xor_result_chars.append(chr(ord(char_code) ^ ord(xor_secret_key[i % len(xor_secret_key)])))
    xor_string = "".join(xor_result_chars)
        
    # 3. salt 추가 및 SHA1 해싱
    final_string_to_hash = xor_string + salt
    hashed_result = hashlib.sha1(final_string_to_hash.encode()).hexdigest()
    
    return hashed_result
# --- Geometry Dash API 관련 유틸리티 함수 정의 끝 ---


# gjp 해시 생성: 함수 호출 결과를 'hash' 변수에 할당
hash = generate_gjp2(password=passwd)

levelString = "H4sIAAAAAAAAC6WQwQ3DIAxFF3IlfxsIUU6ZIQP8AbJChy_GPSZqpF7-A4yfDOfhXcCiNMIqnVYrgYQl8rDwBTZCVbkQRI3oVHbiDU6F2jMF_lesl4q4kw2PJMbovxLBQxTpM3-I6q0oHmXjzx7N0240cu5w0UBNtESRkble8uSLHjh8nTubmYJZ2MvMrEITEN0gEJMxlLiMZ28frmj"

data = {
    "gameVersion": 22,
    "accountID": accid,
    "gjp": hash, # 이제 'hash' 변수가 정확히 정의되어 있습니다.
    "userName": user,
    "levelID": 0,
    "levelName": lname,
    "levelDesc": "Q3Vyc2VkIGxldmVsIG55ZWghaGVoIGhlaCBhbnl3YXkgaXRzIGEgdmVyeSBicm9rZW4gbGV2ZWwgaSBzZW50IGEgcmVxdWVzdCB0byByb2Igc2VydmVyIHRocm91Z2ggcHl0aG9uIGxvbA",
    "levelVersion": "-47577473775738573",
    "levelLength": 48483845738573486574873869465947694,
    "audioTrack": 0,
    "auto": 0,
    "password": 314159,
    "original": 55610687,
    "twoPlayer": 0,
    "songID": 839583504693858468444987694,
    "objects": 1,
    "coins": coin,
    "requestedStars": stars,
    "unlisted": 0,
    "ldm": 0,
    "levelString": levelString,
    "seed2": generate_chk(key="41274", values=[generate_upload_seed(levelString)], salt="xI25fpAapCQg"), # 정의된 함수 사용
    "secret": "Wmfd2893gb7"
}

headers = {
    "User-Agent": ""
}

url = "http://www.boomlings.com/database/uploadGJLevel21.php"

req = requests.post(url=url, data=data, headers=headers)
print(req.text)

향후 예방을 위한 팁

  • 외부 코드 사용 시 주의: API 문서나 예제 코드를 참조할 때는 호출 방식뿐만 아니라, 해당 함수나 클래스의 정의(구현)가 함께 제공되는지 반드시 확인해야 합니다. 누락된 부분이 있다면 직접 구현하거나 다른 자료를 찾아야 합니다.
  • 종속성 명확히 파악: 프로젝트에 사용되는 모든 함수, 클래스, 변수가 어디에서 오는지 (내부 정의, 특정 모듈 임포트 등) 명확히 이해하고 있어야 합니다. 파이썬의 NameError는 이러한 종속성이 제대로 충족되지 않았을 때 가장 흔히 발생합니다.
  • 아카이브된 문서 활용 시 주의: 아카이브되거나 오래된 문서는 정보가 불완전하거나 최신 API와 호환되지 않을 수 있습니다. 가능한 한 최신 공식 문서를 참조하고, 필요한 경우 관련 커뮤니티의 도움을 받는 것이 좋습니다.
  • 재사용 가능한 모듈화: 만약 generate_chk와 같은 유틸리티 함수를 직접 구현한다면, 이를 별도의 파일(예: gd_utils.py)로 분리하고 필요할 때 임포트하여 사용하는 것이 코드의 가독성과 재사용성을 높이는 좋은 방법입니다.
  • 단위 테스트: 핵심 로직을 담당하는 함수(예: generate_chk)에 대해서는 단위 테스트를 작성하여, 함수의 동작이 예상대로 이루어지는지 검증하는 습관을 들이면 좋습니다. 이는 특히 외부 API와의 인터랙션에서 중요한 데이터를 생성하는 함수에 유용합니다.

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다